One advance I'm really hoping for in the future is driverless cars. I really hate driving,
unless it's at ludicrous speed! That's just fun. My requirements for the driverless car
are very simple. I need it to accept a location, drive me to the destination, and wake me when
it gets there. I really don't care what company does it first or how it gets done. The car
just has to be capable of performing my three tasks.
You can think of these car tasks as a contract of three methods for a class. Set location,
drive, and wake me up. That's what an interface is. It's a contract that states any class
implementing this interface can be typed as the interface and it guarantees the methods
listed in the interface will be implemented. So let's talk about how interfaces work, and
how we can use them in our applications.
When defining an interface, we use the keyword "interface" instead of class. That's pretty
much the biggest difference. Interfaces must be public or package scope. If we don't specify
the scope of the interface, it's protected.
We can have attributes in an interface, but the catch is all attributes must be public,
static and final. That's a constant. Even if we don't declare the attribute scope, Java
makes the attribute public, static and final. The reason is interfaces are contracts, they
can't hold state. If we need state, we should use classes.
Sometimes we'll see a constant interface pattern. The idea is we put a ton of constants in an
interface, and we add the interface where we need it. It's a bad idea, and it's considered
an anti-pattern. If you ever find yourself wanting to create a constant interface, put
the constants in a final class.
For the most part, interfaces are only method declarations, and we do not implement any
of the methods. We'll cover the exception later.
When we talk about interfaces, we're not talking about the is-a relationship we see with inheritance.
We say the class implements or does x. We use the keyword "implements" on our class.
If we use the interface as a type, it points to a class instance that implements the interface.
We cannot create an instance of an interface. Sometimes we see interfaces used to describe
an "is-a" relationship as well. It's usually when the interface is used as the type for
the class. I prefer to use the words "does", "acts like", or "implements" when describing
the relationship between interface concepts.
We can create a hierarchy of interfaces. In this case, we're extending the contract of
methods with more methods. In this case, we'll use the keyword "extends".
In Java we usually add the word "-able" after the name. So if the interface's purpose is
to be self driving, we might name the interface SelfDriveable. It's a weird convention, and
you'll see some very strange mental gymnastics to create an interface name that can end in
"-able". My recommendation is to try your best, but if the interface name would be clearer
with out the "-able" suffix you can skip it. The other option is to prefix the interface
with the word "Can", as in CanSelfDrive.
Recently the people at Java ran into a situation where they were painted into a corner. Most
of their collection classes are defined using interfaces. They wanted to add functional
programming to their interfaces, but if they changed the interface it would break every
class using the interface. The interfaces are a fundamental part of Java, so it would
break other people's code.
To solve this problem, they added something called default or defender methods to interfaces.
Defender methods enable us to add new functionality to interfaces and ensure binary compatibility
with code written for older versions of those interfaces.
This means we can provide default functionality for some methods. To do this, we use the keyword
"default" when defining the method, and provide the default implementation of the method.
Defender methods can lead to a situation where two interfaces provide a defender method with
the same name. In this case, the code will not compile and we cannot use the two interfaces
together.
When we have an interface that extends another interface, we can call any super interface
defender method. We do this using the interface name with the super keyword.
Sometimes you'll see an interface containing no methods at all. It's just an empty interface.
These are called marker interfaces. They inform the compiler the objects of the classes implementing
the marker interface need to be treated differently.
An example of this in Java is the Serializable interface. Serializable says this object can
be copied, stored to disk, and then recreated. There are conventions, but there are no methods
we are forced to implement. Java won't let you serialize an object unless you tell the
compiler it's ok. The marker interface does that by checking for the interface type.
There's one other type of interface. It's called a functional interface. This is an
interface containing exactly one method. It's also marked with something called an annotation.
The annotation isn't required. The annotation lets the compiler know it should enforce single
abstract method inside the interface. These interfaces are important for functional programming
and lambdas. We'll cover those later, but you should be aware of what is a functional
interface.
The first thing that might come to mind is, how are these different from abstract classes?
An abstract class is a partially completed class. It's up to us to complete the class
when we derive from it. Since it's a class, you can only inherit from a single class.
If we want to add or change behavior, abstract classes force us to use inheritance.
Interfaces say we promise to implement the methods listed in the interface, but there's
no limit to the number of interfaces our class will implement. Our classes are free to use
as many interfaces as needed. That's why I say "does" is a better relationship word for
interfaces. A class usually represents one concept, but it can "do" many actions.
The most common use for interfaces is to hide the details of a class. If we look at the
List interface in Java, it contains many methods for manipulating a list. Behind the interface
curtain, there are many types of lists. There's an ArrayList, a LinkedList, a Vector and so
on. With the list interface, we're separating what each class does from how it does it.
The actual class used doesn't matter.
If we need to change the class behind the scenes, say a different class handles large
lists better than the one we're using, we can swap the class without needing to change
much code. This is called programming to an interface.
In most cases, we want to avoid inheritance. We should use abstract classes only when we
want to include functionality, but parts of the class's purpose need to be implemented
by the child class. With abstract classes, you are forcing other developers to implement
child classes using inheritance. Interfaces are much easier to add to existing classes,
and with defender methods there is little reason to not consider interfaces first.
OK, that was another very long tutorial. Thank you for making it to the end!
If you have any questions let me know in the comments. Liking the video helps me understand
what I'm doing right, so if you liked the video... you know what to do.
And with that, I’ll see you in the next video!