1z0-808 Oracle Java SE 8 Programmer – Abstract Classes and Interfaces part 2
- Interfaces: Part 2
We create these interfaces and then these interfaces in turn are implemented by classes. So just like an abstract class, you can never create an instance of an interface. You can never just say new interface. That’s not legal. In Java, there is a concept called an anonymous class which we don’t cover in this course. And the syntax makes it look like you’re creating a new interface. But you’re never just of saying new interface. And what the interface is doing is it’s setting up a contract. It’s defining the behavior that is expected by all of the classes that implements this particular interface. A class can implement any number of interfaces it chooses to do. So I’ll show you how that looks in a minute.
But it’s just a comma separated list of all of the interfaces. And when we do that, what we’re saying is that this class overrides the methods that have been defined in the interface. At least it overrides the abstract methods in the interface. So here’s an example of the Cat class using the Implements keyword. So now we’ve got the public class Cat and it’s extending animal extends animal. That makes a lot more sense than extends Shape. After you specify your Extends, if you have something that you’re inheriting directly from you, then say Implements and then the name of the interface.
So Public Class Cat Extends Animal Implements drawable And then what we do is we implement, or I should say, override all of the methods that were defined in the interface. And because cat implements drobble and drawable has the draw method, then by extension, cat must override draw. If it doesn’t, just like we were seeing with the abstract classes, the compilation would fail. It would say, what are you doing? You said you were drawable and you haven’t implemented this abstract method and it will fail. So now here’s our revised hierarchy. Notice that we’ve got the drawable interface and both Shape and Cat will say that they implement that interface.
Circle and Rectangle extend Shape and everything looks pretty good. Now of course, we could have said circle implements drawable and rectangle implements drawable. But the nice thing about what we’re seeing here is that by saying Shape, Implements drawable, that means if we make a brand new class later, let’s say a triangle. And if we say Triangle extends Shape, then we by just the hierarchy that’s already been set up, we are saying that triangle also implements Drabble. So that’s one of the nice things about these diagrams, by the way. The diagrams that we’re looking at, they’re a form of uml, unified modeling language. So what we’re seeing here is you just kind of go up the line.
So circle extends shape. Shape is implementing the drawable interface. Therefore, Circle implements the drawable interface. It’s just implied by the hierarchy. And so, like I said, by having Shape implement the interface rather than each class, then we’re saying for the future, if someone creates a brand new class like Triangle, then they too automatically implement drawable. And as you can see, both Circle and Rectangle must implement all of the methods. They have to do Area and they also have to do Draw. Notice that Shape doesn’t have to implement the Draw method. Why is that? Well, remember that Shape is an abstract class.
And I said one of the rules about abstract methods is that they must be overridden by any concrete class. Well, Shape is not a concrete class, it’s an abstract class. So it’s not bound by those rules. It can override whatever method it wants and it doesn’t have to override any that it doesn’t. If it doesn’t override a method such as Draw, which is what it’s doing, it’s not overriding the method, then it’s passing the buck. It’s saying, okay, whoever extends Shape now has to implement the Draw method. And that’s really the behavior that we want to see. So here’s an example of what Circle looks like. We’ve got our public abstract class, Shape, which implements drawable.
Note once again that we do not have the method Draw in that abstract class, though we could have. And if we did have Draw implemented in Shape, then Circle wouldn’t have to, they could circle could override it if it would like, but it wouldn’t have to. Same thing with Rectangle, same thing with Triangle and so on. But the Shape class did not override Draw. So Circle does Circle now overrides Area, which is the abstract method defined in Shape, and it overrides Draw, which is the method that was created in drawable. And now Circle can be passed into any variable that’s expecting either a Circle, a Shape or a drawable. And that will continue on for any future class that’s made that extends Shape.
If you extend Shape, then you’re going to have to override both Area and the Draw method or declare your new class to be abstract as well. And remember that to override a method successfully, you’re going to have to match that signature and you’re going to have to follow all the rules that we’ve talked about before on what it means to override a method. So an interface can be visualized with a few different analogies. I like this one the best that an interface is a contract. And so when a class says I implement this interface, what they’re saying is yes, I agree that I will provide implementations of all the abstract methods that have been defined in this interface. You can also think of an interface as like a role that the class plays.
So in some cases my Circle will behave like a shape because it is a shape, but in other times it will behave just like a drawable object, which is its role. Also an interesting thing about creating interfaces, interfaces can extend other interfaces. And what that means is that an interface can inherit all of the methods that were defined in another interface. Let’s say I’ve got Interface A and Interface B. And Interface B. Extends interface A. And now I say that I implement Interface B. That means by definition I implement both Interface B and Interface A. I don’t have to explicitly write that for the implementing class, I just have to say I implement Interface B and if Interface B extends any other interfaces, well then I’m implementing those as well.
Now let’s talk about this concept of a default method. A default method is one that includes a body. So it’s just a normal method, but it has the default modifier as well. And here’s what it would look like in my interface I’ve got a draw method. There are now curly braces which normally wouldn’t be there. And then we just have our method, the body of the method. So why do we have to put the word default if it’s just a normal method? And that’s really about backwards compatibility because until we were able to even add default methods, which was Java eight, any method that didn’t say abstract, the compiler would say AHA, I know you’re abstract, I’ll add that modifier for you.
So because of that rule and because of backwards compatibility we just have another modifier that we have to add. Because of this. The default modifier is something you’re only going to see in interfaces. You won’t see them in abstract classes, you won’t see them in concrete classes, they’re not necessary in those constructs. And the purpose of a default method is that it gives us the opportunity to say I’m going to add some new methods to my interface and it won’t break people that have already been implementing the interface. So what I mean by that is imagine that you implement an interface and the rule of the interface is that you got to override all the methods, right? If I say I implement drawable, then I’ve got to override all the methods that are abstract and drawable.
So if I added another abstract method and then put it into the code base and you pool the new code, try to compile again your code breaks because you are no longer implementing all the abstract methods. So now we can put a default method here and you can decide whether or not you want to override the method. Here’s an example. I’ve got a class Rectangle that implements drawable. I’m able to call Draw inside of rectangle. Even though I didn’t override the method. It’s legal because there is a default implementation in the interface. The only kind of drawback about using the default implementation is that when they write a default implementation in the interface, it doesn’t have access to any instance variables.
And that’s because it is a method that only has access to what’s available in the interface itself. And what kind of state do we have in the interface? We just have constants public static and final. So no instance variables are available to a default method, but that’s only if you’re relying on the default implementation. If we override draw here in Rectangle, then sure we have access to all of the instance variables of Rectangle, but the default implementation does not. So that’s default methods. What about static? Static methods are very similar to default methods, but with two exceptions. First of all, they’re going to list the static modifier instead of default. And then they’ll also have to follow all the rules that we’ve talked about with static methods.
The other thing that’s interesting is that concrete classes don’t actually inherit static methods in the same way that they do default. And if you think of the terminology that explains why, remember that we said that one of the rules about overriding methods is that you can’t really override a static method. You can hide a static method, but the problem is that or not the problem, but the way it’s used is that a static method is going to be invoked by the reference type, not by the real runtime object. So think polymorphically person p equals new employee. Person is the reference type, employee is the actual run type. So if we call a static method on P, it’s not going to call the static version that’s an employee. It’s going to call the static version in the reference type, which is person.
So concrete classes don’t actually inherit the static methods. We’ll have to access them like we would any other static method. And here’s an example of that. I’ve got drawable with a public static void drawn. It’s got some kind of implementation. If I want to access that method, I can’t just say draw, which we see right here. Like we could do that with the default method, right? That was perfectly legal. But with a static method it’s going to say, what are you talking about? Rectangle doesn’t have a method called draw. So even though we implement a drawable, we do not inherit the static methods. I also can’t say rectangle draw for pretty much the same reason. Rectangle doesn’t have draw, but I can say drawable dot draw. That’s legal.
- Interfaces: Part 3
And now, just like abstract classes, we’re posed with the same question why? Why do I have to learn interfaces? What’s it going to do for me? And the answer is really the same. It’s going to allow us to employ polymorphism because what we can do now is create variable reference types that are interface types, just like we were doing with abstract classes. So now we can store a circle, a rectangle, a cat at all of these things in a drawable reference variable. So for example, I’ve got drawable D one that’s going to have a cat. drawable D two has a circle and then we can call draw on both of those objects. Now of course, you may think, well, couldn’t I have just created a cat and call Draw? Couldn’t I have created a circle and call Draw? Certainly.
But now this reference variable can store any of those. And then when we hit the code that wants to draw, we don’t really care if it’s a cat or a circle. We’ve abstracted that. We’ve said we just know that you’re drawable and we want you to draw. Now, could I say D two area? D two is a circle. It has area, but the answer is no. Remember the rules about polymorphism that when we’re calling methods, when we are reading or writing to instance variables, that it’s going to look at the reference type to see what’s available. And the method area is not available to drawable. The method area is available to circle, it’s available to shape, it’s not available to drawable.
So what we could do is cast it just like we were doing with abstract classes. So here I’ve got my D two reference. I’m casting it to be a circle. Remember, we put parentheses around that whole casting so that it gets done first and then we call area. That’s legal. And now we can make polymorphic methods as well. So I’ve got a print method that takes a drawable. And in this method what we’re saying is we don’t really care what you are. We don’t care that you’re a circle, a rectangle, a cat. We’ve abstracted that away. We’ve simplified this. We just know that you’re something that can be drawn and that we can call the draw method on it. That’s the power of polymorphism.
Now, interfaces also give us the ability that we can implement many interfaces at the same time. And so this is kind of a way of giving us multiple inheritance, something we don’t get from extending classes. Now, a class, remember, can only extend one class, but we can implement any number of interfaces. And here’s an example of that. So I’ve got my public class, Foo. We’re implementing drawable, runnable serializable and any other interface that we want to implement. The only rule we got to follow is that we make sure we override all of the abstract methods that these interfaces contain. But this flexibility does add another rule and this is because of the addition of default methods in Java Eight.
If you happen to implement two or more interfaces and they have default methods, not abstract but default methods, and the default methods have the same signature, then this class that’s implementing the interfaces must override the methods. So we’ve got class foo here. It’s implementing drawable and runnable. If drawable and Runnable had the same method signature as a default method, then foo would be required to override it. We wouldn’t be able to use the default implementations. Why is that? Well, think about it. There’s an ambiguity there which of the default methods should be called.
If we’re relying on a default method and we implement more than one interface that has this exact signature, which one should be called? Since we don’t know and the Java platform doesn’t know, it forces us to override the method in the class itself. When you create an interface, you’ll be tasked with coming up with a good name interface. Names are typically adjectives or they include the word listener or maybe even the word interface in the name. A lot of the interfaces end with a bull like we saw drawable. If you look at the Jdk and look at the API that’s available, you’ll see a ton of these runnable serializable cloneable. We have some that use the listener syntax.
So action listener. Ultimately it’s up to you how you name your interfaces. But this is fairly common. Our employee is really going to be the only things that get paid for by the system. Maybe we’ve got other companies and other people that need to be paid and we’d love to use that cut Chetting service to issue the checks. So rather than having cut check take an employee, maybe we should have something that accepts an interface, maybe a Payable interface so we could rewrite Pay service to take a Payable. And what we’re saying now is, well, you might be an employee. We don’t know, we don’t really care. We just know that you’re something that’s Payable. And we know that if you’re payable that we’ll be able to call this method Pay.
It’s a method that was defined in the Payable interface. And so we’ve got this Payable interface. It would look like this public interface payable. Notice it says public double Pay. We don’t have the word abstract, so it’s assumed to be abstract. If we had default, if we had static, then that would be assumed to be default and static. But if it was default or static, we wouldn’t be able to just have a semicolon right here at the end. We would have curly braces and a body for that method. And now anything that actually needs to be paid simply has to implement the Payable interface. In fact, now we can really improve the architecture of our employee so we could make employee abstract, which is what I really wanted to do.
Remember I said I’m not really happy with the fact that the Pay method could return zero. I don’t even want you to ever create a new employee. I want to make sure that we enforce all subtypes of employee like programmer and instructor. I want to make sure that they override the method pay. And those are the objects that I actually want you to instantiate. So by making employee abstract while still implementing the Payable interface, then that’s going to pass that buck to all the subtypes. It’s going to say all employees must implement the Pay method. And you can never say new employee. This is perfect. So it would look like this public abstract class employee extends person implements Payable.
- Abstract Classes and Interfaces Lab
The primary purpose of our Good class is really to set up polymorphism and to share state and behavior amongst all of the different types of good. But we really don’t want someone to instantiate a good object. We simply want to use it for polymorphism. I don’t want to see new Good written in my code. I do want to see methods that accept good parameters or maybe an instance variable that’s of type good. So what we’re going to do is we’re going to turn good into an abstract class to prevent anyone from instantiating it. We’re also going to look at creating an interface called Product and we’ll have the Good class implement that interface as well. So the instructions for this lab are in the resources section. This is lab number eleven and the PDF you’re going to download is called Lab Eleven. Abstract interface solutions are at the back of the lab and let me know if you have any questions.