1z0-808 Oracle Java SE 8 Programmer – Inheritance
- Section Overview
In the beginning of this course, we mentioned that objectoriented programming languages are very extensible, easily extensible. And so that’s one of the things that we’re going to see in this particular section called Inheritance. So we’re going to see how we can take an existing class and then add stuff and change stuff to create a more specialized version of it.
- Inheritance: Part 1
When we look at the classes that we build for our applications, we often find that there’s a lot of similar structures, a lot of similar functionality in multiple classes. And of course we could rewrite everything over and over and over again, or we could take advantage of object oriented programming and reuse some of the code between the classes.
So one of the ways that we can do that is to take the common functionality and put that into a separate class which everyone else is dependent upon. And that follows the whole dry principle I mentioned before. Don’t repeat yourself. So if you find that the same code is written over and over and over again, maybe it makes sense for that code to be in its own object. We have, for example, the My Date class. And My Date can be reused in a whole number of classes. People have dates, we’ve got such as birth dates and anniversaries. Companies have dates such as the fiscal year IPO. Date orders have dates such as shipping and billing dates and so on.
So what we can do is reuse that My Date class in a whole bunch of other classes itself. So look at person. Here we’ve got Person and it has a first name and a last name and that’s some reuse right there as well. String is an object. We are taking all the functionality of what it means to be a string, putting it in one object and then reusing that in our custom classes. Same thing with address that we have down below and below that we’ve got the My Date. So here we’ve got our date of birth that we’ve just created. And so this act of taking other classes and using it to build our own class here is called Composition.
So we are being composed of other objects. Composition is one tool that we can use for code reuse, but the other is inheritance. So let’s look at the problem and then we’ll fix it. So this is an employee and employees using Composition. It’s using Strings and address objects, it’s using My Date and so on. And we also have what’s kind of cool here is we’ve got two My Dates, right? We’ve got a My Date for the date of birth and then we’ve got a My Date for the higher date as well. So we are using Composition to build another type of object, an employee. But if we look at this we’ll see that we’re still repeating ourselves. An employee makes sense, right?
That they have a first name, a last name, a home address and so on. But if I jump back to the person, all of that information is in person too. The only thing that’s different is that we went in and we added two new fields. We’ve got a higher date in the salary and we added a new method, promote. And so this is a style of coding, probably the oldest methodology of coding called the copy and paste coding. And it’s something we don’t want to do. We want to make sure we follow and adhere to the Dry principle. Why? Once again, what happens if we change our strategy, our tactic of what it means to be a person? Well not only do to go into the person class that we have here and make that change, I’m going to have to find every other type that’s in our project and follow those same rules. And if I don’t, then we’re going to have an inconsistent application.
- Inheritance: Part 2
So composition is a really great tool for achieving code reuse, but it’s not the only tool. One other thing I want to say about composition is that it follows what’s called the has a rule. And so if you’re wondering if you should use composition, one of the things that you can say is put the words has a into a sentence with the type and the class. Let me give you an example. An employee has has a first name. An employee has a last name, an employee has a home address and so on. And so that shows this is great. This is a great usage of composition because the has a rule has passed. So there’s another similar rule. It’s called the Isa rule. And inheritance describes an Isa relationship. For example, the employee is a kind of type or person. And we can just say write in a sentence, an employee is a person. Does that make sense? And the answer is, yeah, that makes sense. How about an employee is a higher date? Doesn’t really make as much sense, right? An employee is a salary. No, an employee has a higher date. An employee has a salary, but an employee is a person. And while there’s a lot of debate about how strictly you should follow these rules, it’s a nice way to start, it’s a good way to help you start thinking about how to organize your classes.
So let’s look at this code that we have here. We’ve got our public class employee. And the way that we set up the inheritance structures, we say extends person. So extends is the key word here to say we are doing inheritance. An employee is a person. But you don’t write Isa, you write employee extends person. Now, one of the benefits of inheritance is pretty obvious. Look at all the code that we just got rid of, right? We had all that code that we were repeating that had originally been in person, and we just basically cut and pasted right into our employee class. Now by saying extends person, we can get rid of all that code, but it’s still part of the class that we created. All that person code that we had originally is still a part of employee. To show you what I mean by that, look at the code at the very bottom. So here we’ve got our employee equals new employee.
And then we’re going to promote employee. Now that’s a method you can see up here was added to the employee class, but we can also do e, get full name. Now, you don’t see get full name as a method in employee, but it is in person and we extend person. So not only do we get to type less with the inheritance relationship, but we get to reuse all that code that was available in the class that we’re inheriting from. So when you extend another class, you inherit all the attributes and all the behaviors of the superclass. In other words, you get all of the methods and the instance variables that in this case were in the person class. You might be thinking, I’d love to inherit from a lot of classes. In that case, well, we do have a restriction. Java is a single inheritance object oriented programming language which means that each class can only extend one class.
There are other languages like C plus that have multiple inheritance where you can inherit from multiple classes, but that is not available in Java. Well, it’s not available in Java, but there are some other features in Java that kind of help us get similar functionality. A little bit later we’ll talk about interfaces. When we’re describing inheritance, whether you’re reading about it or you’re talking to a fellow developer, there are a number of different ways that people will describe inheritance. If we look at the Java syntax, we saw that we use the word extends. An employee extends person. Sometimes you’ll hear people say that the top level class, the person in this case is the super class, and then the employee is the sub or the subordinate class. Some people will say that person is the more general class and employees the more specific. So you can think about a person has some general functionality, some general state and behavior, whereas an employee has all that, but some more specific state and behavior as well, such as a salary and the method promote. Educators such as myself tend to like the idea of a parent and child relationship.
So the person would be the parent and the employee would be the child. And I like that one in particular because it does give you a little hint about the rules of object creation and that when we have inheritance, the parent class must be created before the subclass the child. So parent child kind of keeps that terminology in the front of your mind. So back to this idea of inheritance being single inheritance in Java, you might think, well, that’s too bad, there’s a number of classes I’d like to inherit from, but the fact is you can actually inherit from multiple classes, just not directly. So for example, we’ve got a person and we said that an employee inherits from our person. So an employee extends person.
Well, what if I want to make multiple types of employees, like an instructor? So now I can say an instructor extends employee and I get everything in that entire inheritance chain. So in this case here, we’re adding the method get schedule. And so I can call Get schedule on an instructor. Let’s just do that. We’ll create the instructor object here’s. George and I can call Get schedule, but I can also call Get full name, which is in the person class as well.
So you get everything in that whole inheritance chain. One other note about the inheritance chain, even though we’re showing just a very single chain here that you can actually have multiple classes inherit from the same class. So what I mean by that is person in this case has employee as a subtype, an employee has an instructor as a subtype. And when we look at each class and go up, each class can only extend one class. An instructor can only extend employee. An employee can only extend person, they can only extend one class. However employee could have lots of subtypes. I could have a class consultant that extends employee and a secretary that extends employee and a manager that extends employee and so on and so on. So you can have a class, can have multiple subtypes, but each class can only have one supertype, one parent.
- Chaining Constructors
Let’s add a few constructors to our person class. So here is our person class and we’ve got some state and a little bit of behavior. So we’ve got our first name, last name, home address, date of birth and we also have that method for get full name. Now let’s add some constructors. So the first constructor that we’re making is a construction constructor that accepts a first name, last name, address, my date and it’s going to take all that state and then assign it to our instance variables which makes perfect sense. The purpose of a constructor is to initialize, we’re initializing all of our fields. This seems like a great constructor to add. And now we’re also going to include a no argument constructor just in case. And so in this case we’re adding one that is going to set up some default names and addresses and date of birth and so on. So in this case what’s happening is when you call person and if you don’t pass in any parameters then it’s going to use this.
And if you recall, this is a way for us to chain constructors in the same class. So it’s going to go from this person to this constructor and it’ll pass in Jane Doe. It’s not going to pass in anything for an address, just putting a null and then some my date object for the date of birth. Now if we’re going to have a subclass called employee so an employee extends person, we’re also going to need to add a constructor to the employee class. So that’s one of the first rules about inheritance that’s easy to screw up that every type is going to need their own constructor. In other words, if I create an employee subclass, an employee extends person, I can’t use any of these constructors directly. I can’t say employee E equals new employee and then pass in a first name, last name, address my date. I can’t say employee E equals new employee and then just have a no argument constructor. So it’s not entirely correct to say we don’t inherit the constructors but when you’re instantiating an object we don’t have direct access to these constructors from the parent class.
We have to call a constructor from the type itself. So person has its own constructors. Now employee is going to have to have its own constructor as well. So here’s our employee class that extends person. We’ve added a little bit of state, a little bit of behavior and now we’re going to add a constructor because we have to, we have to have some kind of constructor. Well, I mean we could use the default no argument constructor but that could actually be problematic and we’ll see why in a little bit later. But let’s add a constructor. So we’re going to add a constructor that takes in basically all the same stuff that the person constructor takes except it’s also going to include the state that is specific for the employee, namely the hiring date and the salary. So let’s take a look at this. We’re going to take the first name. We inherit the first name instance variable from person. So we’re going to take F name, which is passed into this constructor, and then assign it to first name, which we inherited. Going to do the same for L name and last name, home address and so on.
And then we’re going to take the new H date and assign that to higher date, take the new Sal and assign that to salary. And now we’ve got a fully initialized object. But we also have a problem. And the problem is that this will not compile. Now why is that? It’s nothing tricky. I’m not doing anything silly like misspelling anything or using poor capitalization. That’s not the issue. And the issue isn’t that we don’t have first name, last name and home address. We do. When you create an employee, those fields do exist with that particular object. Let’s go back to the previous example, person, and see what’s happening. So here’s what’s happening. Notice that first name, last name, home address and so on, they’re all private. And what’s the rule of private? Private is only available inside of the class itself. In other words, yes, I can reference first name here in the person constructor even though it’s private because they’re all in the same class. But in my employee, which we just created, I can’t reference first name in the employee class because it’s not the same class. So does an employee have a first name? Yes, but it can’t access it directly. So there are several ways we can get around this problem. One of the things we could do is just loosen the restriction.
So our access modifier right now is private, which is the most restrictive. We can make it a little bit less restrictive. We could have the default access modifier where there is nothing written, you just leave out the access modifier and that would be the same thing as saying it’s available to the class itself. But really also any other classes that are in the same package, we could make it even a little bit less restrictive than that. We could make it protected. And that was the access modifier I said I would get to once we learned inheritance. So let’s get to it. Protected simply means it’s available to the class itself. It’s available to any class in the same package and it’s also available to any subclass, no matter where it is anywhere else. It doesn’t have to be in the same package. So we could loosen up the restriction if we want to, but then we’re breaking encapsulation, we’re breaking the data hiding and we don’t typically want to do that.
So what other options would we have? Well, we could use the setter and getters right. We could add all of our accessors and mutators as public and that wouldn’t break. Encapsulation could do something like this go back into person and keep the strings private, add some getters and setters and so on. Any issues with that, just take a look, maybe even pause. Do you see any problems? And I’ll tell you it’ll compile, it’ll be fine. Obviously the ellipsis that you’re seeing here, that’s not legal java, but they’re just saying imagine there’s more code. But what do you think will happen here? What are some of the problems? Well, a couple of problems.
Number one now for the rest of the existence of this person object that lives, it’s always going to have public getters and setters, meaning that the state could change. Now imagine that that doesn’t really fit our business rules. What if I don’t want the first name to change? I don’t want the first name and last name to ever change in this person class, by allowing getters and setters we’re saying that, yeah, you can read and you can change these values and maybe we don’t want to do that. The other thing is that we’re putting the burden of how this person object should be created onto the employee. The employee has to not only know, but remember that it needs to call all of these different setters in order to build a complete object. One of the purposes of constructors is not only to initialize the object that we’re creating, but to specifically say this is how you must initialize the object. So by letting us just simply piece this together with one set at a time, we’re opening ourselves up to a number of potential bugs simply by leaving items out or also making the object a little bit more accessible than we really want throughout the life of the application.
So the best way to handle this is with what’s called chain constructors. And we’ve already learned a little bit about chaining constructors with a this keyword. And remember, you say this in parentheses and that will chain from one constructor to another. We can also do that with inheritance. So we use the super keyword to chain constructors from the child class to the parent class. And this is really the cleanest way to code our relationship between the parent and the child. So what’s nice is that we can be in our employee constructor and we can defer to some other constructor. We can chain to some person constructor to pass in the data that it’s expecting and needs. So here’s an example of doing just that. We’ve got our employee constructor and now what we’re doing is we’re using super so that we can call the constructor that is in the person class passing in the Fname L, name add and date of birth. And now because we’re calling the constructor, the person object is able to construct itself appropriately and we’re done with it. This is the proper way to initialize objects with inheritance.
So after that’s done, we then set our higher date, we set our salary and we’re ready to go. Even when a subclass doesn’t call that super explicitly, the compiler will put that in there for you. Here’s an example. What if we did go down that path where we were calling setters for everything? Even though you don’t see a call to the super constructor here one will be placed in there for you. You’ll never see it. It’s in the bytecode, it’s not going to be in your source code, but in fact, when you compile it, this is what gets put in there. We get this super no argument constructor call and that just gets added to the first line if you don’t explicitly call a super constructor yourself. So you can imagine that that might be a problem. What if the parent class doesn’t have a no argument constructor? Well, if that was the case, you’d get the following error that you’re seeing below. So it’d say cannot find symbol. A symbol is just a name. It’s an identifier, a name of a method, a name of a field, a name of constructor. And it’s saying I can’t find this symbol constructor person. And what they’re telling you is that there is no argument constructor in the person class. And if you didn’t know that underneath the covers it was adding this call to super, you probably would be wondering why does it care? Why does it need a no argument constructor? And that’s why.
So either you put in an explicit call to super yourself in the constructor or else it will put in one for you. If you recall, there was a rule whenever we chain constructors with this and this had to be the first line of the constructor. Exactly the same with super. Super has to be the first line of the constructor and that tends to make a lot of sense. Remember I said that we have a parent child relationship and the parent must exist before the child does. So what it’s doing is when you call a child constructor, the first thing that constructor is going to do is call the parent constructor so that the parent is fully initialized and ready to go before the child is. If you screw that up, you will get a compiler error. It’ll warn you. It’ll say call to super must be the first statement in the constructor.