1z0-808 Oracle Java SE 8 Programmer – Polymorphism part 1
- Section Overview
All right, continuing on with the concepts of object oriented programming, and this time we’re going to hit the topic of polymorphism. Polymorphism is all about substitutability and it gives us a way to make our applications futureproof in a way and flexible. It is a tough concept, just to be honest, and so we’re going to spend quite a bit of time going over it. By the end, you’ll be ready to work with Polymorphism.
- Polymorphism Demo
Polyamorphism has a pretty rough reputation in regards to how difficult it is to learn the concept. It’s not just a Java thing, it’s an objectoriented programming concept. And so it’s, it’s considered to be tough across the board. But I really think it’s a fairly simple concept when you focus on what, what benefits we get from it, how it’s used, instead of kind of getting immediately lost in the syntax and the rules that are applied. So what I want to do is just kind of go through a short scenario here with you so you can see Polymorphism in action. And I think once you’re aware of what it does, the benefits that we get, that I think learning the rules is just a lot easier. So let’s imagine a scenario where you’ve been hired as a developer to code an inventory manager.
The company builds cars and trucks and different kinds of automobiles. And they do have a team of developers who have been working on cars and trucks. But their resources are thin. They need people to be hired to build this inventory manager. So there you are, you got a gig and you take a look to see what they’ve done already and you see that they build a car. That’s what I’m showing you right now. And obviously, I’m just showing you the skeletons of these classes and they’ve got a truck. And you’ve noticed that both of these classes extends automobile. So you take a look at automobile and if you remember back to our car example, this is kind of familiar.
We’ve got a Vin count and every time an automobile is instantiated, it’s going to increase that Vin count and then assign that to the local variable of Vin. So you see that there’s inheritance going on. You see that they’re doing encapsulation. So this is pretty good. They’ve got a pretty strong foundation here for you to work with. So you go in and you build your inventory manager. And you’re familiar with the concept of overloading methods. So rather than confusing them with add truck, add car and lots of different names, you said, let’s make this easy on everyone. Just remember add automobile and you can pass in a car or you can pass in a truck and it should just work out of the box.
And so you do your work and they’re ready to test the application you built. And so they’ve got a car dealership, they instantiate the inventory manager you built and they’re going to instantiate a car, throw that into your manager and need to the add automobile method doing the same thing with the truck. Let’s run it. And there you can see we’ve got an adding car and we’ve got the 202 for the ID and we’ve got adding truck. And this one ends with 203. And so everything is working great, everyone is really happy. And a little bit later you get a call and they say, you know, what, we’ve been working on some more vehicles. We now have a motorcycle and we’d like you to add that to the system. Can you do that? And you say, sure, let’s take a look at the motorcycle.
And the motorcycle extends automobile. It’s basically the same kind of thing you’ve been working with. So you say, yeah, that’s not a problem. And you go in, and so you add a new method here public void keeping along with the same name to make it easier for the car dealership to use. You say add automobile. So same name, but this one’s going to accept a motorcycle. And we’ll do what we did before. We’ll just print out that we’ve added a motorcycle. So adding motorcycle. All right, there’s our method. Let’s go back to the car dealership and add the motorcycle. Motorcycle test C equals new motorcycle. And we’re using that manager to add the motorcycle. And what I do, we have car C. We want motorcycle M.
That would be much, much better. There we go. All right, everything’s looking good. So no compile errors. Let’s run it. And there it is. It added the motorcycle. So the system works. Everyone is really happy, and you go off and you start another gig. And now you get a phone call and they say, hey, we’ve got yet another vehicle. It’s a scooter. And they send it to you to take a look at. And you’re like, you know, it looks fine. This is a great scooter. You’re still using inheritance, everything looks perfect, but I’m on another gig. I can’t help you with this. I’m really sorry. So now they’re stuck. Now they have to go in and figure out how did you actually build this inventory manager. And remember, we’re just looking at a skeleton of what you actually built.
So there’s a learning curve there and they have to take time from other projects and so on to work on this particular class. Wouldn’t it have been kind of cool if we could have simplified this a bit? What if we could have just said instead of us every single time having to go back into this code and say, add another overloaded method? What about if we just had one method and we could add adding automobile and instead of accepting a car, we just take an automobile. Now, we weren’t creating automobiles, right? We were creating new cars, new trucks, new motorcycles. But what if we said we’ll take an automobile and that just worked, that you could in fact give me a car? Well, let’s look at the car. Again, a car extends automobile. And remember, the is a rule.
A car is an automobile, truck is an automobile, motorcycle is an automobile. So again, wouldn’t it be cool if we could just say we’ll take any kind of automobile, as long as it is an automobile, we can accept it. So if we wrote this method, and we just did, didn’t we and now let’s go look at the car dealership. I want you to notice there’s an absence of something here. There’s an absence of red X’s. There are no compile errors here at all. This works. This just works out of the box and that’s it, guys. That’s all that polymorphism is. Polymorphism means that we can substitute one object for another as long as they’re of the same type. So in my inventory manager, when I say I accept automobile, what I’m really saying is I’ll accept an automobile or any subtype of an automobile.
And car, truck, motorcycle, scooter, they’re all subtypes. In fact, we didn’t even add a scooter yet. But let’s do it. Scooter S Equals new Scooter manager. Add automobile. Scooter. No compile error. Run it and it works. Other than my spelling error down here. Right, that’s no good. But other than that, it it just works. So that’s it. That’s what polymorphism is. It’s just the ability to substitute one object for another. And did we really have to do anything to make this work? We didn’t, right? Every time in Java you have a reference variable. The type of the reference variable is saying, I accept this type or any subtype. It’s just built into the language. So that’s it, guys. That’s polymorphism. What we’re going to do is now dive into some of the rules that go along with using polymorphism. But keep this example in the back of your mind as we continue on with the next lecture.
- Polymorphism: Part 1
So you’ve had the opportunity now to see polymorphism in action and you saw that it’s really easy to set up. There are no special keywords that you have to learn. It’s really just about how to apply something that’s built into the language. And what’s built into the language is this simple idea that anytime we have a reference variable inside of Java that that reference variable can store the object type it specifies or any subtype. And what that allows us to do is make applications that are very, very flexible and also future proofed and all that. I mean by saying future proof is that we can build another object that’s of the same type and it should just work with that method. That’s the best case scenario that it just happens to work.
We saw an example before where I showed you we added a scooter to our inventory manager and because the scooter extended automobile, it worked with all the methods that just said we accept automobile and that’s it. But regardless, it’s still a little bit of a struggle for a lot of people when they are learning Java and when they’re learning object oriented programming language. So we’re going to have yet another example and we’re going to dive a little deeper into the rules of Polymorphism. Now regarding the name, the name has Greek origins. It loosely translates to many forms but most people tend to use the term substitutability. So in programming it means a class has the same interface or set of methods but different implementation.
So with our automobile the same method was get the Vin, we could get the vehicle identification number. Now in our particular implementation they were all using the same method but we could have overridden that method and the car could have had a different implementation from the truck, from the motorcycle and so on. So that’s the real use of Polymorphism. Not only for a method to be able to accept many different types of objects but then to be able to send the same message to whatever object they get. And each object can then respond in its own way. Now, I realize that that’s a little bit abstract to imagine your head. So we are going to hit an example here in just a minute.
So Polymorphism is all about substitutability, the ability to say I take this type of an object and then at runtime anyone can pass in any object provided as of that type. So let’s look at a couple of examples. First line employee e equals new employee. That’s your regular let’s create an employee syntax. But what we also can do because of Polymorphism is we could say person p equals e. The second line right here and we can do that because an employee extends person. It’s part of the same family. So if the rules of polymorphism are we will accept person or any subtype, then this is perfectly legal. In fact, we could do it all in one line if we wanted to person p equals new employee. And then if we looked on the stack, this is what we would have.
We’ve got re, which is referring to the employee, and we’ve got p, which is also referring to the exact same employee. Now you might wonder, why would I do that? Now, you were on board when you saw the example about the automobile, but this is a little weird. Why would I ever say person p equals new employee? And the fact is you probably won’t. You probably won’t, or at least you won’t do it often where you’ll just have a reference type and you’ll list a new subtype. There’s use cases where that makes sense, but here’s what you’re normally going to do. Let’s jump to some code for a second. So I’m in my inventory manager here and I’ve got a reference variable, an instance variable that is of type automobile. It’s a featured auto.
And we also have a method here called add featured auto, which will take an automobile. So what I’m going to do now is just invoke this method, I’m going to pass in an automobile, which is then going to be stored in this automobile. Instance variable, let’s do that. So I’m going to go to my car dealership. On line nine, we’re creating a car, car C equals new car. And line eleven, this is where we’re calling that ad featured auto. Now think about what it would look like in terms of having all the frames on the stack, what the variables would be. In a way when I say car C equals new car, and I call this ad featured auto, I could have and to clean this up, I’m just going to comment out that line next to it.
I could have, for convenience sake, really just passed in this new car, right? I could have gone in here and just said, oops, missing a parenthesis. So what I could have done is said new car and pass that right into the ad featured auto. Hopefully that makes sense. What I’m doing right here, just creating a new car, passing it into the featured auto. So going back to that method, what’s really happening? Well, on the frame, there’s a frame being added for add featured auto. And in that frame, I’ll just write some code right above here’s my frame. And so in the frame there’s going to be an automobile and its reference name is auto. And what is the value? Well, the value was the new car that we just passed in, right? Let’s go back here.
We are creating a new car. We’re passing it into that method. That method gets its own frame. And so what is it doing? It’s setting up this variable automobile auto. And the value is the new car that we passed in. That makes sense, right? So now up here, even though we’re not seeing it, this automobile this featured auto is really equal to the new car we passed in temporarily anyway, right? So would you write person P equals new employee? Maybe not as much. Would you write automobile featured auto equals new car? Probably not as much. But what you will do is you’ll have this variable, you’ll have this instance variable that accepts a polymorphic type.
And so when you invoke the method passing in that new car, you’re essentially doing the same thing as saying automobile featured auto equals new car. Right. Going back to the code here. So that’s all we’re saying. A lot of times you’re not going to do this all in one line, but maybe you have a method that accepts a person and you want to pass in a new employee. Maybe you have an instance variable that’s of type person and you set it to be an employee. So that’s the flexibility of polymorphism. We’re saying that we’ll accept a person of any type.
- Polymorphism: Part 2
Okay, so continuing on, this is the syntax. Our reference type will store any object type that is of the same reference type. In other words, person P would store a new person. Or if the object type is a descendant of the reference type, then that’s perfectly legal. The opposite is not true. Let’s look at this code. Right here we have employee e equals new person. That will not work. And if you think about it logically, it makes sense. In our application, all employees are persons. Which means that when we send a message using all the things that are available to a person, the employee can respond. But imagine we do this. We’ve got an employee equals new person. So on the heap at Runtime, we actually have a person object.
And during compile time, we can send any messages that are legal to an employee. So if I was to say e promote or E get salary, would the person object actually have a salary? Would they have a method called promote? And the answer is no, they won’t. So Java just stops you from doing that right away. Java says you can’t do this, it’s illegal, won’t even let you compile. And you can always use the Isa rule just to check to see if it should work. Person p equals new employee. So what you do is you start on the right side. An employee is a person. It’s right here. A person is an employee. Well, some people are, but not all right. A person doesn’t have to be an employee, so it won’t work. Now, that’s it. That’s the syntax of applying polymorphism.
There’s a couple of more rules we’ll hit. But getting back to why do we use polymorphism? It really promotes the flexibility and separation of concerns. The real power of polymorphism, however, ties into overriding methods. So remember, overriding methods means we are taking a method we inherited and we are going to create a new implementation. We have the exact same method signature and we are just going to provide a different way that it should work. So let’s look at another example with the person employee class. So here I’ve got my person class. It has a first name and a last name and a get description. And then I have an employee that extends person. It has a title and it’s overriding git description.
So what happens now when we create an object of type employee and call that method? So we say person P equals new employee, our person is storing an employee. Now, if I say P get description, is it legal to call that P get description? And the answer is yes. The reason it’s legal is because if you look at the person class, there is a get description method available. But here’s what happens at Runtime. At Runtime. And this is called dynamic method dispatching. What’s going to happen is that the request for get description is going to come into here, into the employee, and it’s going to say employee, do you have a Git description? And the answer is yes. So this is the one that will run at Runtime.
And so what it’s going to do is it’s going to print out an employee and then we’re calling super get description. Remember, that what super does is it’s going to go to the parent. It says don’t look for Git description right here. Because if we just said get description and got rid of super, we’d actually have infinite recursion. It would just keep going until we’d see a stack overflow exception. So our stack overflow error, really it’s not an exception. We’ll talk about errors versus exceptions in a little bit. So we’ve got our super get description and that’s going to go up here. It’s going to write in person, it’s going to return the first name and last name, which will then be concatenated with the colon and the title.
So let’s just say that the first name last name is Jason Shapiro. The title is instructor. When we say P get description, it would say in employee, in person, Jason Shapiro, colon title. All right, just from calling that P get description. So there’s another example. If the names was John Smith and it was Instructor, it would say in employee, in person, John Smith, Instructor. So even though the reference type variable is of type person at Runtime, it sends a message to the actual object. And so the actual object will run its version of the method. And that’s why overriding methods are so popular. And by the way, that’s why final is really interesting with the method because you can stop that from happening.
You can say, well, now that I know with polymorphism we could do a person peakals new employee. If I want to make sure that employee doesn’t change the way Git description works back in person, I could have said get description is a final method and then we wouldn’t be able to override it. So again, that’s known as dynamic method dispatching. What happens is the virtual machine looks at the actual Runtime object, in this case an employee, to see if it has get description. And if it doesn’t, then it just keeps going up the inheritance street trying to find it. And also when you have final methods, that’s why it executes faster because it doesn’t need to dynamically figure out where the method is defined, it knows where the last place is.
So even though the actual method is discovered at Runtime, the compiler has some rules and the rule is fairly simple, it just takes a while to get used to it. But this is the rule. Whenever I have a reference variable, person p, I don’t care what you say on the right side here, I don’t care that you put new employee. When I use P, the only variables I can look at, the only methods that I can call are those that are available to P to person, not to employee. So if I try to say P title equals instructor, which is something only an employee has that will not compile and that can be really frustrating. When you first learn this, you might look at this and say, but I can see it, it’s a new employee, it says it right there.
Doesn’t matter the way that the compiler works and the way that Java works is that it says I’ve got a person variable, so I can only send messages that a person can react to. So that code is illegal. At Runtime, the Jvm will figure it out. AHA, ah. This is actually an employee object, but at compile time it really doesn’t know what that object is, it just knows that P is a person. In this particular case, the compiler is going to go, well, let’s double check that title is something that a person can see and they’ll say, Nope, that’s not something that a person can see, it’s nothing that a person would have. So the compilation will fail.