1z0-808 Oracle Java SE 8 Programmer – Abstract Classes and Interfaces part 1
- Section Overview
This is the final section in which we are going to be talking about the pillars of objectoriented programming, and this one is based on abstraction. Specifically, we’re going to look at abstract classes and interfaces to see how we can create a consistency among our program. And also, again, like polymorphism, introduce substitutability and flexibility into our apps. So let’s hit that first lecture.
- Abstract Classes: Part 1
We’ve talked about several different pillars of objectoriented programming. We’ve seen encapsulation, inheritance, polymorphism, and now we’re going to look at abstraction. Although we’ve been dealing with abstraction for most of this time. In this course, I’ll give you an example. Well, actually, let me define it and then I’ll give you an example. So the definition of abstraction is really to simplify to, to take something that’s complex and break it up in a way that we can deal with it in a more general manner. If you think about in the polymorphism chapter, we had all those different employees and we had a pay service.
The employee class itself was a form of abstraction because our pay service didn’t really think about is it talking to an instructor or is it talking to a programmer? And so on. All that it cared about was it’s talking to an employee and it’s able to ask it, what is your pay? But in fact, the message was really getting to a more specific object, the instructor, the programmer and so on. And their implementation of pay was hidden, was abstracted away from the pay service. That’s the basic idea of abstraction. But we have a couple of other constructs we can use to help us implement abstraction. And so we’re going to start with the abstract class.
So again, abstraction is all about generalization and that’s what we’re using abstract classes for. So this is particularly useful when we are capturing similarities between classes. So let’s take a look at an example of a rectangle and a circle. So I’ve got two different classes. Here our circle, I’ve got our rectangle. And if you take a look, you’ll notice that there are some things that are different, but there are some things that are the same. Mainly the behavior is the same. They both compute an area. Now they do it in a different way. Circle is going to use pi R squared and rectangle is going to use height times width.
But in terms of behavior, if we abstract what they’re doing, they’re both computing area. And so when we find these kind of similarities like we’re seeing in the area method, then that can give us a chance or an opportunity to say, can we work with these type of objects in a more general way? Are they related in some way? And so here the similarity between the two is that they’re really, they’re both shapes. So maybe we can create a more generalized abstract class called a shape. The problem though is once we pull area into this super class, into this shape class, there’s no real good way to define what that area method should look like.
What does a general area method for a shape do? It’s the same kind of problem we saw with employee. Remember I was kind of complaining. I said, I’m not really happy with the fact that employee has this method pay that returns zero. That just doesn’t sit well with me. So I mean, it’s the same problem here. We’ve got a shape, public class shape, but the area method, what do we put in the body? What should it do? So luckily, Java gives us this construct that we can work with, this modifier to say we’re defining a method signature, but we’re not going to put a body in it. And it’s known as an abstract method. And all that you do is put the abstract modifier in front of the name. You also have to make sure that there’s no code block, no curly braces.
In other words, abstract methods have absolutely no implementation.So here’s an example. I’ve got the public Abstract method double area, there’s no curly braces, there’s no body for that method, it’s just the signature. And what we’re doing is we’re saying we’re creating a method that should be used polymorphically. We’re saying that this is a method we want available to all shapes. But when you say that it’s abstract, then that’s going to force any subtypes to implement that method, specifically to override it. And I really need to emphasize this point. When you make a subtype, something that extends an abstract class, the rule is you must implement all of the abstract methods.
If you don’t, the only way that you can get around that is if you say I’m abstract as well. And what I mean by an abstract class is simply adding the abstract modifier to the class declaration. So you can see it right here, public Abstract Class Shape as long as I put abstract in front of a class, then it is not required to implement all of the abstract methods that it may have inherited. So if I’ve got a rectangle class and that extends shape, rectangle is going to have to implement area. And that’s a good thing, right? That’s what we’re trying to do. Think back to the employee class. We want to make sure that every employee subtype implements the pay method.
And by making the method abstract, then they will have to, they’re forced to by the compiler. The only way they can get around it is if the employee, or in this case the shape, also said I’m also abstract. In that case, you don’t have to implement every abstract method, but as soon as you have a concrete class, which is just a class that is not abstract, that means that all of the abstract methods that have been defined in any of the ancestors must have some concrete implementation. Otherwise the concrete class will not compile. Anytime you have a class that has even one single abstract method, then the entire class has to be declared abstract as well.
And what that means is that you can’t instantiate it. You can’t ever say new shape. And if you think about it, that’s probably a good thing. Again, go back to our idea of the employee class that we had for the pay service. The employee was there to share state, to share behavior amongst all the different kinds of employees. But we’re never going to say new employee. And wouldn’t it be cool if we could be prevented, let’s say someone’s new to the team and they don’t realize that and they start creating new employees in our program. Wouldn’t it be great if the compiler would stop them and say, no, you can’t do that? Well, abstract classes, that’s exactly what happens when you try to say new shape or new employee.
If we had made the employee class abstract, then it would say, no, you can’t do that. We can’t instantiate an abstract class. Another kind of cool feature of abstract classes is that they can actually contain concrete methods, methods that are not abstract. So you can have real methods that do things. But the purpose of an abstract class is really just so that it can be used polymorphically, so that it can be extended. So we’ve got shape as an abstract class and we’ve got circle and rectangle that will extend that shape. And so the abstraction is really in the shape. The shape is just going to define some general behavior. Any shape can compute an area, but it’s the subtypes circle and rectangle that are really doing all the hard work. That’s abstraction.
- Abstract Classes: Part 2
The way that we create an abstract class is simply by applying the abstract modifier to the class. And remember, if anytime we have even a single abstract method in our class, we have to declare the class itself to be abstract. So that’s all you have to do. Now the question is, why do we use it? And of course, I’ve already mentioned this several times. The reason is polymorphism. So what we’re doing is when we create this abstract relationship between, say, rectangle and circle through the Shape class. Now we can write methods that say, I don’t really care if it’s a circle or a rectangle. I just care that it’s a shape. And I’m only going to be sending messages to it that have been defined in Shape.
Just like the Pay service was saying. Don’t really care if it’s an instructor, don’t really care if it’s a programmer. I just know that they’re an employee and that’s how I’m going to interact with them. I know that all employees are going to have a Pay method, so that’s all I really care about. But you also get the added bonus that the compiler will then stop you from actually creating an object that should have never been made, such as the Shape object. We want shape reference variables. We want to be able to accept Shape parameters, but we don’t want to be able to make a Shape object. We want a circle, we want a rectangle. The same thing with the employee. I don’t want an employee object.
I want to be able to accept employees. So I want employee parameters. I want employee reference variables. But I don’t want you to make a new employee. I want you to make a new instructor. So now that we’re going to use an abstract class, this is what we have. We’ve got our circle and rectangle that we had before and that they are now extending Shape. And Shape is an abstract class with an abstract method called area. And as you can see, abstract classes, they don’t actually reduce code. That’s one of the things that we were talking about with inheritance. We’re saying if this is great because it reduces code, you only have to write what’s different.
That’s not the way abstract classes work. We’re not reducing in fact, we’re adding code, but we’re setting ourselves up to be able to use these objects polymorphically. And here’s an example. It sounds like a big word when I say that use these polymorphically. But this is all that I mean that we can create a method called area difference and we can take any shapes. We’re taking two shapes as parameters. And then to compute the area, we’re going to take the area of the first shape, subtract the area of the second shape, and return that value at this moment in time inside of the area difference method. We don’t really care what the shape is. We don’t care if it’s a circle.
We don’t care if it’s a rectangle, we only care that it’s a shape. And so what we’re saying is that this gives us an opportunity to treat all shapes polymorphically. And here’s how it would be instantiated. We’re creating a circle, setting the radius to be ten, creating a rectangle, setting the height and the width, and then passing those objects into area difference. The actual object types are they’re real concrete classes. But when they’re passed into Area Difference, if I jump back here to the method, you can imagine what happens when this is placed on the stack. Area difference gets its own frame on the stack. It has two variables shape s one and shape s two. What is shape s one pointing to? Shape s one is pointing to a circle.
Shape s two is pointing to a new rectangle. So again, this allows us to treat shapes polymorphically. And I do want to show you the error message that you’ll get if you accidentally tried to say new shape. So if you do that, if you ever try to create an instance of an abstract class, this is what happens. So here we’ve got a shape s equals new shape. Soon as I try to compile, this is the error that I would see. Shape is abstract cannot be instantiated. Boom. Just tells you right there what the problem is and why you can’t compile. So let’s recap. Abstract methods have no curly braces, which means they have no body, no implementation, just a signature and a semicolon. If a class has even one single abstract method, then the entire class has to be declared as abstract.
We can’t instantiate an abstract class. You can’t use the new keyword and create an instance of an abstract class. If a class is going to inherit from an abstract class, the rule is it has to implement all of the methods that have been declared abstract. The only way you can get out of not doing that is if the subclass is an abstract class itself. Part of the main reason that abstract classes exist is to create relation between classes so that we can use them polymorphically, but it’s also just to share data, to share methods. Remember that we can have actual concrete data and methods in our abstract classes. Not everything has to be abstract in the abstract classes.
- Interfaces: Part 1
So as we’re building out our circle and rectangle class, we decide that each of the classes should be able to be drawn. And so for each class, we create a draw method, public void draw. And inside the method is all the logic we need to have each of our shapes drawn. And so we get together at a code review and we look at our shapes and we say, you know, circle and rectangle both have this draw method. Maybe we can treat this polymorphically in the same way that we treated Area. And we all agree that’s a great idea. Let’s employ some abstraction here. And we move draw into the shape class.
We create it as an abstract method because how do you draw a generic shape? It’s the same problem as computing a generic shapes area. We just want to make sure that the method is available so that whenever a method says I take a shape object, that they know that they can call area and they know that they can call draw. So the meeting is about to end and everyone’s happy except for one person. And they say, you know, I’ve got a class too. And with this class I have draw. Is there any way that I can be used in all these great methods you guys are coming up with that are accepting shapes? And we say, well, tell us a little bit about the class. And they show it to us.
It’s called public class cat. And they have, just like they said, a method called public void draw. And they’d like to be treated as just like the rectangle and the circle so that they can be drawn as well. And we understand that, but we say, I don’t know, how do we make this work? And they say, it’s not a problem. What we can do is just say public class cat extends shape. And by the rules of polymorphism, now I can pass in a cat to any method that accepts a shape, just like I could pass in a rectangle or a circle. Okay? I mean, technically speaking, that person is correct. But let’s think through the ramifications of doing this.
If we say that a cat extends shape and we have this method, public void draw, will this compile? Will this class compile? And the answer is no, because what is one of the rules of extending an abstract class? You have to implement all of the abstract methods. So now the person that made the cat is also going to have to come up with a method called area. Now sure, we could certainly figure out a way to compute the area of a cat, but probably not recommended. And we’re probably getting outside the scope of what it means to be a cat. And that’s why we have that is a rule. If we can say something is a type of another, then as more and more methods are added to the parent class.
It doesn’t really negatively affect the child class. It makes sense. What I mean by that is if we add any other kind of method to a shape that is related to a shape, it’s reasonable to think that a rectangle and a circle should implement those methods. Okay? But as we add more and more methods that are related to a shape, the cat is going to have to implement all those abstract methods too. And just like that area method, it’s not always going to make sense. And so that’s why we use that as a rule. A circle is a shape. Yep, a rectangle is a shape. Sounds good. A cat is a shape. No, we’re getting outside of the scope of what it means to be a cat. But all is not lost.
What we can do is create something called an interface and this will allow us to treat the cat polymorphically, just like we’re treating the shapes. So what we do is we create an interface, it’s just public interface, and then the name, you replace the Word class with the name interface and then you define your methods. And there’s some rules about the methods we’ll talk about in just a second. But here’s an example. We’ve got the public abstract void Draw in here. And now what we can say is that the cat is going to implement this interface and we can even say shape implements this interface. So it’s another way of adding roles or responsibilities to a group of objects and it allows us to treat those group of objects polymorphically.
So an interface is a pseudo class. Interfaces are going to be defined in their own files. They have the Java extension. So that last interface we just saw would have been drawable Java. We replaced the Word class with the Word interface. So public interface. drawable. All methods that we’re going to put in the interface are public. And then they also have to be one of three types abstract, default or static. Now we’ve already talked about abstract methods, so you know what those are. We’ll talk about default and static coming up. Now, since the public modifier is implied, sometimes you won’t see it. In other words, if you look at an interface and it doesn’t say public, it’s still public.
Public is implicit even if that modifier isn’t written in the file. Also, if we don’t have one of these modifiers, abstract, default, or static, then by default it is assumed to be an abstract method. In addition to the methods, interfaces can also contain variables, but they have to be constants. They have to be public, static and final. And because they have to be, all of those modifiers have to be applied. If you don’t put those modifiers on, they are assumed. So just remember that when you run into abstract methods in an interface that they follow the exact same rules as abstract methods in abstract classes.
Interestingly enough, up until Java se eight, that was the only kind of method that we could have in an interface. Once eight came out, we had default and static methods that were added to the language. And we’re going to define those in the next lecture. But do keep in mind, if you look at any old blog posts, read any old books or see videos, that they may mention that interfaces can only contain abstract methods. And that was true for many, many years. But as of sea, that is no longer true. We do have these other types of methods, so let’s talk about those in the next lecture.