Hello! Today we’ll talk about an important concept in Java - interfaces. The word is probably familiar to you. For example, most computer programs and games have interfaces. In a broad sense, an interface is a kind of “remote control” that connects two parties interacting with each other. A simple example of an interface from everyday life is a TV remote control. It connects two objects, a person and a TV, and performs different tasks: turn up or down the volume, change channels, turn on or off the TV. One side (the person) needs to access the interface (press the remote control button) for the other side to perform the action. For example, for the TV to switch the channel to the next one. In this case, the user does not need to know the device of the TV and how the process of changing the channel is implemented inside it.
All the user has access to is the interface . The main task is to get the desired result. What does this have to do with programming and Java? Direct :) Creating an interface is very similar to creating a regular class, but instead of the word
You worked with interfaces
class
we specify the word interface
. Let's look at the simplest Java interface and figure out how it works and what it is needed for:
public interface Swimmable {
public void swim();
}
We created an interface Swimmable
that can swim . This is something like our remote control, which has one “button”: the method swim()
is “swim”. How can we use this “ remote control ”? For this purpose the method, i.e. button on our remote control needs to be implemented. To use an interface, its methods must be implemented by some classes of our program. Let's come up with a class whose objects fit the description “can swim.” For example, the duck class is suitable Duck
:
public class Duck implements Swimmable {
public void swim() {
System.out.println("Duck, swim!");
}
public static void main(String[] args) {
Duck duck = new Duck();
duck.swim();
}
}
What do we see here? A class Duck
is associated with an interface Swimmable
using the keyword implements
. If you remember, we used a similar mechanism to connect two classes in inheritance, only there was the word “ extends ”. “ public class Duck implements Swimmable
” can be translated literally for clarity: “a public class Duck
implements the interface Swimmable
.” This means that a class associated with an interface must implement all of its methods. Please note: in our class, Duck
just like in the interface , Swimmable
there is a method swim()
, and inside it there is some kind of logic. This is a mandatory requirement. If we just wrote “ public class Duck implements Swimmable
” and did not create a method swim()
in the class Duck
, the compiler would give us an error: Duck is not abstract and does not override abstract method swim() in Swimmable Why does this happen? If we explain the error using the example of a TV, it turns out that we are giving a person a remote control with a “change channel” button from a TV that does not know how to change channels. At this point, press the button as much as you like, nothing will work. The remote control itself does not change channels: it only gives a signal to the TV, inside of which a complex process of changing the channel is implemented. So it is with our duck: it must be able to swim so that it can be accessed using the interface Swimmable
. If she does not know how to do this, the interface Swimmable
will not connect the two sides - the person and the program. A person will not be able to use a method swim()
to make an object Duck
inside a program float. Now you have seen more clearly what interfaces are for. An interface describes the behavior that classes that implement that interface must have. “Behavior” is a collection of methods. If we want to create multiple messengers, the easiest way to do this is by creating an interface Messenger
. What should any messenger be able to do? In a simplified form, receive and send messages.
public interface Messenger{
public void sendMessage();
public void getMessage();
}
And now we can simply create our messenger classes by implementing this interface. The compiler itself will “force” us to implement them inside classes. Telegram:
public class Telegram implements Messenger {
public void sendMessage() {
System.out.println("Sending a message to Telegram!");
}
public void getMessage() {
System.out.println("Reading the message in Telegram!");
}
}
WhatsApp:
public class WhatsApp implements Messenger {
public void sendMessage() {
System.out.println("Sending a WhatsApp message!");
}
public void getMessage() {
System.out.println("Reading a WhatsApp message!");
}
}
Viber:
public class Viber implements Messenger {
public void sendMessage() {
System.out.println("Sending a message to Viber!");
}
public void getMessage() {
System.out.println("Reading a message in Viber!");
}
}
What benefits does this provide? The most important of them is loose coupling. Imagine that we are designing a program in which we will collect customer data. The class Client
must have a field indicating which messenger the client uses. Without interfaces it would look strange:
public class Client {
private WhatsApp whatsApp;
private Telegram telegram;
private Viber viber;
}
We created three fields, but a client can easily have only one messenger. We just don't know which one. And in order not to be left without communication with the client, you have to “push” all possible options into the class. It turns out that one or two of them will always be there null
, and they are not needed at all for the program to work. Instead, it's better to use our interface:
public class Client {
private Messenger messenger;
}
This is an example of “loose coupling”! Instead of specifying a specific messenger class in the class Client
, we simply mention that the client has a messenger. Which one will be determined during the course of the program. But why do we need interfaces for this? Why were they added to the language at all? The question is good and correct! The same result can be achieved using ordinary inheritance, right? The class Messenger
is the parent class, and Viber
, Telegram
and WhatsApp
are the heirs. Indeed, it is possible to do so. But there's one catch. As you already know, there is no multiple inheritance in Java. But there are multiple implementations of interfaces. A class can implement as many interfaces as it likes. Imagine that we have a class Smartphone
that has a field Application
- an application installed on a smartphone.
public class Smartphone {
private Application application;
}
The application and the messenger are, of course, similar, but still they are different things. Messenger can be both mobile and desktop, while Application is a mobile application. So, if we used inheritance, we would not be able to add an object Telegram
to the class Smartphone
. After all, a class Telegram
cannot inherit from Application
and from Messenger
! And we have already managed to inherit it from Messenger
, and add it to the class in this form Client
. But a class Telegram
can easily implement both interfaces! Therefore, in a class Client
we can implement an object Telegram
as Messenger
, and in a class Smartphone
as Application
. Here's how it's done:
public class Telegram implements Application, Messenger {
//...methods
}
public class Client {
private Messenger messenger;
public Client() {
this.messenger = new Telegram();
}
}
public class Smartphone {
private Application application;
public Smartphone() {
this.application = new Telegram();
}
}
Now we can use the class Telegram
as we please. Somewhere he will act in the role of Application
, somewhere in the role of Messenger
. You've probably already noticed that methods in interfaces are always “empty”, that is, they have no implementation. The reason for this is simple: an interface describes behavior, not implements it. “All objects of classes that implement the interface Swimmable
must be able to float”: that’s all the interface tells us. How exactly a fish, duck or horse will swim there is a question for the classes Fish
, Duck
and Horse
, and not for the interface. Just like changing the channel is the task of a TV. The remote simply gives you a button to do it. However, Java8 has an interesting addition - default methods. For example, your interface has 10 methods. 9 of them are implemented differently in different classes, but one is implemented the same in all. Previously, before the release of Java8, methods inside interfaces had no implementation at all: the compiler immediately threw an error. Now you can do it like this:
public interface Swimmable {
public default void swim() {
System.out.println("Swim!");
}
public void eat();
public void run();
}
Using the keyword default
, we have created a method in the interface with a default implementation. We will need to implement the other two methods, eat()
and run()
, ourselves in all classes that will implement Swimmable
. There is no need to do this with the method swim()
: the implementation will be the same in all classes. By the way, you have come across interfaces more than once in past tasks, although you didn’t notice it yourself :) Here is an obvious example: ![Why do we need interfaces in Java - 2](https://cdn.javarush.com/images/article/dd15b9e7-137d-45f1-8233-51f18c9a41a6/1024.jpeg)
List
and Set
! More precisely, with their implementations - ArrayList
, LinkedList
, HashSet
and others. The same diagram shows an example when one class implements several interfaces at once. For example, LinkedList
it implements the interfaces List
and Deque
(double-sided queue). You are also familiar with the interface Map
, or rather, with its implementations - HashMap
. By the way, in this diagram you can see one feature: interfaces can be inherited from each other. The interface SortedMap
is inherited from Map
, and Deque
is inherited from queue Queue
. This is necessary if you want to show the connection between interfaces, but one interface is an extended version of another. Let's look at an example with an interface Queue
- a queue. We haven't gone through the collections yet Queue
, but they are quite simple and arranged like a regular line in a store. You can add elements only to the end of the queue, and take them away only from the beginning. At a certain stage, the developers needed an expanded version of the queue so that elements could be added and received from both sides. This is how an interface was created Deque
- a two-way queue. It contains all the methods of a regular queue, because it is the “parent” of a two-way queue, but new methods have been added.