Thursday, January 6, 2011

Chapter 7: Object Oriented Concepts - Inheritance

Inheritance is one of the building blocks of Java and it is used extensively in all java based applications. Inheritance is everywhere in Java. I can’t think of one java project that I worked on, where inheritance wasn't used. In order to explore this topic we’re going to use the instanceof operator, which we’ll discuss in more detail in future. For now, just remember that instanceof returns true if the reference variable being tested is of the type being compared to. This code:

class InstanceTest {
public static void main(String [] args) {
InstanceTest t1 = new InstanceTest ();
InstanceTest t2 = new InstanceTest ();
if (!t1.equals(t2))
System.out.println("they're not equal");
if (t1 instanceof Object)
System.out.println("t1's an Object");
}
}

Produces the output:
they're not equal
t1's an Object

You are now probably thinking, where this equals method came from? Remember my standard statement? “Everything in Java is an Object”? Ah Yes, now you remember. Every class that you create invariably (and automatically) extends from java.lang.Object. And this Object class contains the equals method which automatically becomes available for all classes. Cool right? The creators of Java assumed (correctly of course) that all programmers would require some sort of functionality to check if two objects are equal and hence this method is placed in the Object class so that it becomes available to all java classes automatically.

The equals method checks if the two java objects under consideration are equal. By default this method checks for the object instance and since in this cast t1 and t2 are created out of two different new InstanceTest() invocations, they are not equal.

Tip: If you wanna argue you can say that since they are both just a new instance of the InstanceTest class, shouldn't they be equal? Yes, you are absolutely right. That is why java gives us the feature wherein you can override the equals() method inside your class and add the checks you want to place in order to decide if two objects are equal.

Now, the second if condition checks if t1 is an instance of Object (which it automatically is) it succeeds and prints the message on the console.
For the exam you’ll need to know that you can create inheritance relationships in Java by extending a class. It’s also important to understand that the two most common reasons to use inheritance are
• To promote code reuse (You don't want your colleague sitting right next to you to write the same validation code in his class while he can obviously use the better code you have written :-) )
• To use polymorphism

Let’s begin with reuse.

A Class can re-use or in java terms inherit features/code of another class by just extending it.
Ex:

public class Child extends Parent {

}

In the above example by virtue of the extends keyword, all the public code inside the parent class is available for use inside the child class.

A common design approach is to create a fairly generic version of a class with the intention of creating more specialized subclasses that inherit from it. For example:

class Car {
public void goForADrive() {
System.out.println("driving a car");
}
// more code
}

class Ferrari extends Car {
public void takeFerrariForADrive() {
System.out.println("driving a Ferrari");
}
// more code
}

public class TestCars {
public static void main (String[] args) {
Ferrari car = new Ferrari();
car.goForADrive();
car.takeFerrariForADrive();
}
}

Outputs:
driving a car
driving a Ferrari

Notice that the Ferrari class inherits the generic goForADrive() method from the less-specialized class Car, and also adds its own method, takeFerrariForADrive(). Code reuse through inheritance means that methods with generic functionality that could apply to a wide range of different kinds of cars —don’t have to be reimplemented. That means all specialized subclasses of Car are guaranteed to have the capabilities of the more generic superclass. You don’t want to have to rewrite the goForADrive() code in each of your specialized car classes of a racing game.
But you probably already knew that. You’ve experienced the pain of duplicate code when you make a change in one place and have to track down all the other places where that same piece code exists. So it is logically and obviously easier to manage changes if all common code is available at one single place.

The second use of inheritance is to allow your classes to be accessed polymorphically—a capability provided by interfaces as well, but we’ll get to that in a minute. Let’s say that you have a CarLauncher class that wants to loop through a list of different kinds of Car objects, and invoke goForADrive() on each of them. At the time you write this class, you don’t know every possible kind of Car subclass that anyone else will ever write. And you sure don’t want to have to redo your code just because somebody decided to build a new Car six months later.
The beautiful thing about polymorphism is that you can treat any subclass of Car as a Car. In other words, you can write code in your CarLauncher class that says, “I don’t care what kind of object you are as long as you inherit from (extend) Car. And as far as I’m concerned, if you extend Car then you’ve definitely got a goForADrive() method, so I know I can call it.”
Imagine we now have two specialized subclasses that extend the more generic Car class, Ferrari and Porsche:

class Car {
public void goForADrive() {
System.out.println("driving a car");
}
// more code
}

class Ferrari extends Car {
public void takeFerrariForADrive() {
System.out.println("driving a Ferrari");
}
// more code
}

class Porsche extends Car {
public void takePorscheForADrive() {
System.out.println("driving a Porsche");
}
// more code
}

Now imagine a test class has a method with a declared argument type of Car, that means it can take any kind of Car. In other words, any subclass of Car can be passed to a method with an argument of type Car. This code

public class TestCars {
public static void main (String[] args) {
Ferrari ferrari = new Ferrari();
Porsche porsche = new Porsche();
goForADrive(ferrari);
goForADrive(porsche);
}

public static void doDrive(Car car) {
car.goForADrive();
}
}

Outputs:
driving a car
driving a car

The key point is that the doDrive() method is declared with a Car argument but can be passed any subtype (in this example, a subclass) of Car. The method can then invoke any method of Car, without any concern for the actual runtime class type of the object passed to the method. There are implications, though. The doDrive() method knows only that the objects are a type of Car, since that’s how the parameter is declared. And using a reference variable declared as type Car—regardless of whether the variable is a method parameter, local variable, or instance variable—means that only the methods of Car can be invoked on it. The methods you can call on a reference are totally dependent on the declared type of the variable, no matter what the actual object is, that the reference is referring to. That means you can’t use a Car variable to call, say, the takePorscheForADrive() method even if the object passed in is of type Porsche.

IS-A and HAS-A Relationships

For the exam you need to be able to look at code and determine whether the code demonstrates an IS-A or HAS-A relationship. The rules are simple, so this should be one of the few areas where answering the questions correctly is easy.

IS-A

In OO, the concept of IS-A is based on class inheritance or interface implementation. IS-A is a way of saying, “this thing is a type of that thing.” For example, Ferrari IS-A Car. Potato IS-A Vegetable. You express the IS-A relationship in Java through the keywords extends (for class inheritance) and implements (for interface implementation).

We will take the same car example as in the previous paragraph. A Car is a type of Automobile, so the inheritance tree might start from the Automobile class as follows:

public class Automobile { ... }
public class Car extends Automobile { ... }
public class Ferrari extends Car { ... }

In OO terms, you can say the following:

Automobile is the superclass of Car.
Car is the subclass of Automobile.
Car is the superclass of Ferrari.
Ferrari is the subclass of Automobile.
Car inherits from Automobile.
Ferrari inherits from both Automobile and Car.
Ferrari is derived from Car.
Car is derived from Automobile.
Ferrari is derived from Automobile.
Ferrari is a subtype of both Automobile and Car.
Returning to our IS-A relationship, the following statements are true:
“Car extends Automobile” means “Car IS-A Automobile.”
“Ferrari extends Car” means “Ferrari IS-A Car.”

And we can also say:

“Ferrari IS-A Automobile” because a class is said to be “a type of” anything further up in its inheritance tree. Figure 2-2 illustrates the inheritance tree for Automobile, Car, and Ferrari. The arrows move from the subclass to the superclass. In other words, a class’ arrow points toward the class from which it extends.

HAS-A

HAS-A relationships are based on usage, rather than inheritance. In other words, class A HAS-A B if code in class A has a reference to an instance of class B. For example, you can say the following,

A Ferrari IS-A Car. A Car HAS-A SteeringWheel.

The code might look like this:

public class Car { }
public class Ferrari extends Car {
private SteeringWheel mySteeringWheel;
}

In the preceding code, the Ferrari class has an instance variable of type SteeringWheel, so you can say that “Ferrari HAS-A SteeringWheel.” In other words, Ferrari has a reference to a SteeringWheel. Ferrari code can use that SteeringWheel reference to invoke methods on the SteeringWheel, and get SteeringWheel behavior without having SteeringWheel-related code (methods) in the Ferrari class itself.

Ferrari class has a SteeringWheel, because Ferrari declares an instance variable of type SteeringWheel. When code invokes turn() on a Ferrari instance, the Ferrari invokes turn() on the Ferrari object’s SteeringWheel instance variable.

HAS-A relationships allow you to design classes that follow good OO practices by not having monolithic classes that do a million different things. Classes (and their resulting objects) should be specialists. The more specialized the class, the more likely it is that you can reuse the class in other applications. If you put all the SteeringWheel-related code directly into the Ferrari class, you’ll end up duplicating code in the Porsche class, Subaru class, and any other class that might need SteeringWheel behavior. By keeping the SteeringWheel code in a separate, specialized SteeringWheel class, you have the chance to reuse the SteeringWheel class in multiple applications.

Users of the Ferrari class (that is, code that calls methods on a Ferrari instance), think that the Ferrari class has SteeringWheel behavior. The Ferrari class might have a turn(Full360) method, for example. Users of the Ferrari class should never have to know that when they invoke the turn() method, the Ferrari object turns around and delegates the call to its SteeringWheel class by invoking mySteeringWheel.turn(Full360). The scenario just described might look like this:

public class Ferrari extends Car {
private SteeringWheel mySteeringWheel = new SteeringWheel();
public void turn(Angle full360) {
mySteeringWheel.turn(full360);
}
}

public class SteeringWheel {
public void turn(Angle full360) {
// Do the actual turn work here
}
}

In OO, we don’t want callers to worry about which class or which object is actually doing the real work. To make that happen, the Ferrari class hides implementation details from Ferrari users. Ferrari users ask the Ferrari object to do things (in this case, turn a full 360 degrees), and the Ferrari will either do it or, as in this example, ask someone else to do it. To the caller, though, it always appears that the Ferrari object takes care of itself. Users of a Ferrari should not even need to know that there is such a thing as a SteeringWheel class. That is how a well designed OO system should work.

Types of Inheritance:
We shall wrap up this chapter by looking at the different types of inheritance that is available. They are:
1. Single Inheritance
A Scenario where one class is inheriting/extending the behavior of just one super class.

Ex: public class Ferrari extends Car {…}

2. Multilevel Inheritance

A Scenario where one class is inheriting/extending the bahavior of another class which in turn is inheriting behavior from yet another class.

Ex: public class Automobile {…}
Public class Car extends Automobile {…}
Public class Ferrari extends Car {…}

This multilevel inheritance actually has no limitations on the number of levels it can go. So as far as java goes, it is limitless. But for maintenance and ease of use sakes it is better to keep the inheritance levels to a single digit number.

3. Multiple Inheritance

Actually, java does not support multiple inheritance. You can achieve partial multiple inheritance using interfaces but java is not like C or C++ where you can do direct multiple inheritance. However, you can achieve partial multiple inheritance with the help of interfaces.

Ex: public class FerrariF12011 extends Ferrari implements Car, Automobile {…}

And this is under the assumption that Car and Automobile are interfaces.

Here if you see, though you don't inherit concrete code from the Car or the Automobile interface, you do inherit skeleton methods that determine the way your class eventually behaves and hence this can be considered partial Multiple Inheritance.

Tip: If you are curious asking me why doesn't java allow multiple inheritance, think about this scenario. Let us say the Automobile Class has a drive() method and the Car class has a drive() method and the Ferrari class has a drive() method too. Let us say you create a new class FerrariF12011 that looks like below:
Public class FerrariF12011 extends Ferrari, Car, Automobile {…}
And at some point of time you need to call the drive() method, what would happen? Your JVM wouldn't know which method to invoke and you may have to instantiate one of the classes that you already inherit in order to call its appropriate method. Sounds confusing right? To avoid this nonsense is why the creators of java did not include this direct multiple inheritance feature.

4. Hybrid Inheritance

This is the scenario wherein your java code exhibits traits of more than one of the inheritance types explained above. Going with the example above again:
Public class FerrariF12011 extends Ferrari implements Car, Automobile {…}
The above is a combination of both single and multiple inheritance.

Previous Chapter: Chapter 6: Object Oriented Concepts - Encapsulation

Next Chapter: Object Oriented Concepts - Polymorphism

13 comments:

  1. Hi Anand,
    Nice article , you have indeed covered the topic in great dettails.

    Thanks
    Javin
    How classpath works in Java

    ReplyDelete
  2. nice article . can we use link exchange.i want to exchange my link with you .
    my blog is corejava1.blogspot.com
    mail me on sridharreddy.kr@gmail.com

    ReplyDelete
  3. Nice article, only, is this what you realy mean:
    goForADrive(ferrari);
    goForADrive(porsche);

    or should be stand:
    doDrive(ferrari);
    doDrive(porsche);

    ReplyDelete
  4. Nice article, only, is this what you realy mean:
    goForADrive(ferrari);
    goForADrive(porsche);

    or should be stand:
    doDrive(ferrari);
    doDrive(porsche);

    ReplyDelete
  5. im still really confused!

    ReplyDelete
    Replies
    1. What are you confused about? Leave a comment with your query and I will try to explain as best as I can...

      Delete
  6. Hi Anand,

    take a look to the below example code you discussed above:

    public class TestCars {
    public static void main (String[] args) {
    Ferrari ferrari = new Ferrari();
    Porsche porsche = new Porsche();
    goForADrive(ferrari);
    goForADrive(porsche);
    }

    public static void doDrive(Car car) {
    car.goForADrive();
    }
    }

    Outputs:
    driving a car
    driving a car

    I think in the above code, the lines:
    goForADrive(ferrari);
    goForADrive(porsche);

    should be replaced with :
    doDrive(ferrari);
    doDrive(porsche);

    Right?

    Also, all you want to convey using this example is that- though we can pass any of the subclass object as a parameter to the doDrive() method of the class Car, we can not call any of the child class method inside the doDrive() method of Car though we have passed child class object as a parameter. We will always be able to call parent class method only.

    Is my understanding correct?

    ReplyDelete
    Replies
    1. Yes, you are right. This is because the doDrive() method is in the parent class and hence the JVM has absolutely no idea of what type of child class object you are going to pass. You can pass a Porsche or a Ferrari. Since both of them are cars, the system can safely call the methods inside the Car class but not what is present inside each of the child objects.

      Anand

      Delete
    2. Thanks Anand for clearing my doubt.

      I had another question-

      If we override goForADrive() method in Ferrari class and then called doDrive(ferrari) (provided ferrari instance of Ferrari) then which goForADrive() method will be called, from inside of parent class (Car) or child class (Ferrai) ?

      Delete
    3. Always the current class will be checked when you do an obj.doSomething() method and if it is not found, then the parents will be checked one by one.


      Here, the parameter passed to doSomething() will not impact which method is called. Instead the obj, which class instance it is, will determine which method is called.

      Is this clear?

      Delete
    4. Yes, if the child class does not contain the implementation for the method to which it is calling then it will go up the inheritance tree untill it finds that particular method.

      Thanks once again Anand!
      I really appreciate your quick reply!

      Delete
  7. Thanks Anand !!!
    As beginner in Java ,It really helped me to understand the concept
    Appreciate your work!!!!

    ReplyDelete

© 2013 by www.inheritingjava.blogspot.com. All rights reserved. No part of this blog or its contents may be reproduced or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written permission of the Author.

ShareThis

Google+ Followers

Followers