Showing posts with label object orientation. Show all posts
Showing posts with label object orientation. Show all posts

Friday, January 7, 2011

Chapter 8: Object Oriented Concepts - Polymorphism:

Polymorphism can be considered as the ability of one thing being multiple other things (though partially or fully). Am I confusing you? I believe yes. To put it in simpler words, any java object that can pass more than one Is-A test can be considered polymorphic. (Remember the Is-A and Has-A relationships that we looked at in the previous chapter?)
Other than objects of type Object, all Java objects are polymorphic in that they pass the IS-A test for their own type and for class Object.

Remember that the only way to access an object is through a reference variable, and there are a few key things to remember about references:
• A reference variable can be of only one type, and once declared, that type can never be changed (although the object it references can change).
• A reference is a variable, so it can be reassigned to other objects, (unless the reference is declared final).
• A reference variable’s type determines the methods that can be invoked on the object the variable is referencing.
• A reference variable can refer to any object of the same type as the declared reference, or—this is the big one—it can refer to any subtype of the declared type!
• A reference variable can be declared as a class type or an interface type. If the variable is declared as an interface type, it can reference any object of any class that implements the interface.

In the previous chapter on Inheritance we crdriveed a class Car that was extended by two other classes Ferrari and Porsche. Now lets say you want to add a fdriveure “open hood” to the cars. Not all cars have a retractable hood but at the same time you want this fdriveure for certain sports models of Ferrari and Porsche. How would you implement this?

Can we create a class with the openHood() method and only some of the subclasses of Ferrari or Porsche inherit from them? If we can do that then we can implement the feature wherein only selected models of Ferrari or Porsche sports cars can do that. But, unfortunately that wont work in Java. Remember the part on Multiple Inheritance towards the end of the last chapter? You cannot have a class that extends from two classes at the same time. So a code like this would never work:

Public class Porsche911TurboConvertible extends Porsche, Convertible {

}

A class cannot extend more than one class. That means one parent per class. A class can have multiple ancestors, however, since class B could extend class A, and class C could extend class B, and so on. So any given class might have multiple classes up its inheritance tree, but that’s not the same as saying a class directly extends two classes.

So if that doesn't work, what else options do we have? We could simple put the openHood() code inside Car class and disable the method in cars that cant open their hood. But, that is really bad design choice owing to multiple reasons. It makes the code error-prone, makes the class Cars less cohesive and it means that as per the code inside the Car class, all cars can open their hoods but the fact is only certain models can do that.

So what else could you do? You already know the answer—crdrivee a Convertible interface, and have only the Car subclasses that can open their hoods implement that interface. Here’s the interface:

public interface Convertible {
public void openHood();
}

And here’s the modified Porsche class that implements the interface:

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

So now we have a Porsche that passes the IS-A test for both the Car class and the Convertible interface. That means a Porsche can be trdriveed polymorphically as one of four things at any given time, depending on the declared type of the reference variable:
• An Object (since any object inherits from Object)
• A Car (since Porsche extends Car)
• A Porsche (since that’s what it really is)
• An Convertible (since Porsche implements Convertible)

The following are all legal declarations. Look closely:
Porsche porscheCar = new Porsche();
Object o = porscheCar;
Car shape = porscheCar;
Convertible mover = porscheCar;

There’s only one object here—an instance of type Porsche—but there are four different types of reference variables, all referring to that one object on the heap.
This is polymorphism – the scenario where one object can be perceived or considered as multiple things.

There are two other important topics that we shall cover in this chapter:
• Method Overloading and
• Method Overriding

Overridden Methods

Any time you have a class that inherits a method from a superclass, you have the opportunity to override the method (unless, as you learned in the earlier chapters, the method is marked final). The key benefit of overriding is the ability to define behavior that’s specific to a particular subclass type. The following example demonstrates a Porsche subclass of Car overriding the Car version of the drive() method:

public class Car {
public void drive() {
System.out.println("Generic Car Driving Generically");
}
}

class Porsche extends Car {
public void drive() {
System.out.println("Porsche driving Full Throttle");
}
}

For abstract methods you inherit from a superclass, you have no choice. You must implement the method in the subclass unless the subclass is also abstract. Abstract methods must be implemented by the concrete subclass, but this is a lot like saying that the concrete subclass overrides the abstract methods of the superclass. So you could think of abstract methods as methods you’re forced to override.

The Car class creator might have decided that for the purposes of polymorphism, all Car subtypes should have an drive() method defined in a unique, specific way. Polymorphically, when someone has an Car reference that refers not to an Car instance, but to an Car subclass instance, the caller should be able to invoke drive() on the Car reference, but the actual runtime object (say, a Porsche instance) will run its own specific drive() method. Marking the drive() method abstract is the Car programmer’s way of saying to all subclass developers, “It doesn’t make any sense for your new subtype to use a generic drive() method, so you have to come up with your own drive() method implementation!” A (non-abstract), example of using polymorphism looks like this:

public class TestCars {
public static void main (String [] args) {
Car a = new Car();
Car b = new Porsche(); //Car ref, but a Porsche object
a.drive(); // Runs the Car version of drive()
b.drive(); // Runs the Porsche version of drive()
}
}
class Car {
public void drive() {
System.out.println("Generic Car Driveing Generically");
}
}
class Porsche extends Car {
public void drive() {
System.out.println("Porsche driving Full Throttle");
}
public void brake() { }
}

In the preceding code, the test class uses a Car reference to invoke a method on a Porsche object. Remember, the compiler will allow only methods in class Car to be invoked when using a reference to a Car. The following would not be legal given the preceding code:

Car c = new Porsche();
c.brake(); // Can't invoke brake();
// Car class doesn't have that method

To reiterate, the compiler looks only at the reference type, not the instance type. Polymorphism lets you use a more abstract supertype (including an interface) reference to refer to one of its subtypes (including interface implementers).

The overriding method cannot have a more restrictive access modifier than the method being overridden (for example, you can’t override a method marked public and make it private). Think about it: if the Car class advertises a public drive() method and someone has an Car reference (in other words, a reference declared as type Car), that someone will assume it’s safe to call drive() on the Car reference regardless of the actual instance that the Car reference is referring to. If a subclass were allowed to sneak in and change the access modifier on the overriding method, then suddenly at runtime—when the JVM invokes the true object’s (Porsche) version of the method rather than the reference type’s (Car) version—the program would die a horrible death. Let’s modify the polymorphic example we saw earlier in this section:

public class TestCars {
public static void main (String [] args) {
Car a = new Car();
Car b = new Porsche(); //Car ref, but a Porsche object
a.drive(); // Runs the Car version of drive()
b.drive(); // Runs the Porsche version of drive()
}
}
class Car {
public void drive() {
System.out.println("Generic Car Driveing Generically");
}
}
class Porsche extends Car {
private void drive() { // whoa! - it's private!
System.out.println("Porsche driving Full Throttle");
}
}
If this code compiled (which it doesn’t), the following would fail at runtime:
Car b = new Porsche(); // Car ref, but a Porsche
// object , so far so good
b.drive(); // Chaos at runtime!


The variable b is of type Car, which has a public drive() method. But remember that at runtime, Java uses virtual method invocation to dynamically select the actual version of the method that will run, based on the actual instance. A Car reference can always refer to a Porsche instance, because Porsche IS-A Car. What makes that superclass reference to a subclass instance possible is that the subclass is guaranteed to be able to do everything the superclass can do. Whether the Porsche instance overrides the inherited methods of Car or simply inherits them, anyone with a Car reference to a Porsche instance is free to call all accessible Car methods. For that reason, an overriding method must fulfill the contract of the superclass.

The rules for overriding a method are as follows:
• The argument list must exactly match that of the overridden method. If they don’t match, you can end up with an overloaded method that you didn’t intend on creating.
• The return type must be the same as, or a subtype of, the return type declared in the original overridden method in the superclass.
• The access level can’t be more restrictive than the overridden method’s. (public to private not allowed)
• The access level CAN be less restrictive than that of the overridden method. (private to public allowed)
• Instance methods can be overridden only if they are inherited by the subclass. A subclass within the same package as the instance’s superclass can override any superclass method that is not marked private or final. A subclass in a different package can override only those non-final methods marked public or protected (since protected methods are inherited by the subclass).
• The overriding method CAN throw any unchecked (runtime) exception, regardless of whether the overridden method declares the exception.
• The overriding method must NOT throw checked exceptions that are new or broader than those declared by the overridden method. For example, a method that declares a FileNotFoundException cannot be overridden by a method that declares a SQLException, Exception, or any other non-runtime exception unless it’s a subclass of FileNotFoundException.
• The overriding method can throw narrower or fewer exceptions. Just because an overridden method “takes risks” doesn’t mean that the overriding subclass’ exception takes the same risks. Bottom line: an overriding method doesn’t have to declare any exceptions that it will never throw, regardless of what the overridden method declares.
• You cannot override a method marked final.
• You cannot override a method marked static.
• If a method can’t be inherited, you cannot override it. Remember that overriding implies that you’re re-implementing a method you inherited! For example, the following code is not legal, and even if you added an drive() method to Porsche, it wouldn’t be an override of Car’s drive() method.

public class TestCars {
public static void main (String [] args) {
Porsche h = new Porsche();
h.drive(); // Not legal because Porsche didn't inherit drive()
}
}
class Car {
private void drive() {
System.out.println("Generic Car Driveing Generically");
}
}
class Porsche extends Car { }

Invoking a Superclass Version of an Overridden Method

Often, you’ll want to take advantage of some of the code in the superclass version of a method, yet still override it to provide some additional specific behavior. It’s like saying, “Run the superclass version of the method, then come back down here and finish with my subclass additional method code.” It’s easy to do in code using the keyword super as follows:

public class Car {
public void drive() { }
public void changeGear() {
// Useful change gear code goes here
}
}
class Porsche extends Car {
public void changeGear() {
// Take advantage of Car code, then add some more
super.changeGear(); // Invoke the superclass (Car) code
// Then do Porsche-specific change gear work here
}
}

Note: Using super to invoke an overridden method only applies to instance methods. (Remember, static methods can’t be overridden.)

If a method is overridden but you use a polymorphic (supertype) reference to refer to the subtype object with the overriding method, the compiler assumes you’re calling the supertype version of the method. If the supertype version declares a checked exception, but the overriding subtype method does not, the compiler still thinks you are calling a method that declares an exception. Let’s take a look at an example:
class Car {
public void drive() throws Exception {
// throws an Exception
}
}
class Car2 extends Car {
public void drive() { /* no Exceptions */}
public static void main(String [] args) {
Car a = new Car2();
Car2 d = new Car2();
d.drive(); // ok
a.drive(); // compiler error - unreported exception
}
}

This code will not compile because of the Exception declared on the Car drive() method. This happens even though, at runtime, the drive() method used would be the Car2 version, which does not declare the exception.

Examples of Illegal Method Overrides

Let’s take a look at overriding the drive() method of Car:
public class Car {
public void drive() { }
}

Let us take a look at a few examples of overridden drive() methods taking the above version of the method in the Car Class

1. private void drive() {} – Access Modifier is more restrictive
2. public void drive() throws IOException {} – Declares a checked exception that is not defined by the super class
3. public void drive (String road) {} – A legal overload but not an override because the arguments to the method has changed (Don't bother about overload just yet, that is the next paragraph)
4. public String drive() {} – Not an override because of the return type and at the same time, not an overload either because there is no change in the argument list.

Overloaded Methods

Experienced java programmers can clearly identify the difference between overloaded methods and the overridden ones. We just had a detailed look at overridden methods and it is time to take a look at the overloaded ones.

Overloaded methods let you reuse the same method name in a class, but with different arguments (and optionally, a different return type). Overloading a method often means you’re being a little nicer to those who call your methods, because your code takes on the burden of coping with different argument types rather than forcing the caller to do conversions prior to invoking your method. The rules are simple:

• Overloaded methods MUST change the argument list.
• Overloaded methods CAN change the return type.
• Overloaded methods CAN change the access modifier.
• Overloaded methods CAN declare new or broader checked exceptions.
• A method can be overloaded in the same class or in a subclass. In other words, if class A defines a doStuff(int i) method, the subclass B could define a doStuff(String s) method without overriding the superclass version that takes an int. So two methods with the same name but in different classes can still be considered overloaded, if the subclass inherits one version of the method and then declares another overloaded version in its class definition.

Tip: Be careful to recognize when a method is overloaded rather than overridden. You might see a method that appears to be violating a rule for overriding, but that is actually a legal overload, as follows:
public class Car {
public void drive(int y, String s) { }
public void brake(int x) { }
}
class Ferrari extends Car {
public void drive(int y, long s) throws IOException { }
}
It’s tempting to see the IOException as the problem, because the overridden drive() method doesn’t declare an exception, and IOException is checked by the compiler. But the drive() method is not overridden! Subclass Ferrari overloads the drive() method, by varying the argument list, so the IOException is fine.

Legal Overloads

Let us say we have the Ferrari class with a method drive() as below:
Public class Ferrari extends Car {
Public void drive() {…}
}

Below are the legal overload method declarations:

1. public void drive(String destination, String roadToTake) {…}
2. public void drive(String destination, int timeToTake) {…}
3. public void drive(String destination) throws RouteNotFoundException {…}
Assuming that the Ferrari class has the above 3 methods, below are is an illegal overload:
1. public String drive (String destination, String roadToTake) {…} – You cannot have two methods which differ just in the return type. This is not allowed

Invoking Overloaded Methods

When you have multiple methods that have the same name, it is sometimes confusing for the programmer who is analysing the code to determine which method would get called and when. But, the good news is that the compiler does not have this dilemma.

When a method is invoked, more than one method of the same name might exist for the object type you’re invoking a method on. For example, the Ferrari class might have three methods with the same name but with different argument lists, which means the method is overloaded. (Check example methods above)

The compiler checks the list of arguments passed to the method before deciding which method to call. Let us say you call the drive method with only the String argument “Destination” the compiler knows exactly that the 3rd method that takes only one String as argument is the method to be invoked. The other 2 methods wouldn't be touched at all during program execution.
Example:

Public class Ferrari extends Car {
public void drive(String destination, String roadToTake) {…}
public void drive(String destination, int timeToTake) {…}
public void drive(String destination) throws RouteNotFoundException {…}
}
Let us say we have the above Ferrari class.

Public class FerrariTest {
Public static void main(String[] args) {
Ferrari car = new Ferrari();
Car.drive(“Central Railway Station”);
}
}

In the preceding code, the FerrariTest class invokes a drive method with just one String argument. So the compiler scans the Ferrari class to see if there is a method drive() that takes one string argument and since it finds one, it invokes it.

Invoking overloaded methods that take object references rather than primitives is a little more interesting. Say you have an overloaded method such that one version takes an Car and one takes a Porsche (subclass of Car). If you pass a Porsche object in the method invocation, you’ll invoke the overloaded version that takes a Porsche. Or so it looks at first glance:

class Car { }
class Porsche extends Car { }
class UseCars {
public void doStuff(Car a) {
System.out.println("In the Car version");
}
public void doStuff(Porsche h) {
System.out.println("In the Porsche version");
}
public static void main (String [] args) {
UseCars ua = new UseCars();
Car CarObj = new Car();
Porsche PorscheObj = new Porsche();
ua.doStuff(CarObj);
ua.doStuff(PorscheObj);
}
}

The output is what you expect:
in the Car version
in the Porsche version

But what if you use an Car reference to a Porsche object?
Car CarRefToPorsche = new Porsche();
ua.doStuff(CarRefToPorsche);

Which of the overloaded versions is invoked? You might want to say, “The one that takes a Porsche, since it’s a Porsche object at runtime that’s being passed to the method.” But that’s not how it works. The preceding code would actually print:
in the Car version

Even though the actual object at runtime is a Porsche and not an Car, the choice of which overloaded method to call (in other words, the signature of the method) is NOT dynamically decided at runtime. Just remember, the reference type (not the object type) determines which overloaded method is invoked! To summarize, which overridden version of the method to call (in other words, from which class in the inheritance tree) is decided at runtime based on object type, but which overloaded version of the method to call is based on the reference type of the argument passed at compile time. If you invoke a method passing it a Car reference to a Porsche object, the compiler knows only about the Car, so it chooses the overloaded version of the method that takes an Car. It does not matter that at runtime there’s actually a Porsche being passed.

Polymorphism in Overloaded and Overridden Methods

How does polymorphism work with overloaded methods? From what we just looked at, it doesn’t appear that polymorphism matters when a method is overloaded. If you pass an Car reference, the overloaded method that takes an Car will be invoked, even if the actual object passed is a Porsche. Once the Porsche masquerading as Car gets in to the method, however, the Porsche object is still a Porsche despite being passed into a method expecting an Car. So it’s true that polymorphism doesn’t determine which overloaded version is called; polymorphism does come into play when the decision is about which overridden version of a method is called. But sometimes, a method is both overloaded and overridden. Imagine the Car and Porsche classes look like this:

public class Car {
public void drive() {
System.out.println("Generic Car Driving Generically");
}
}
public class Porsche extends Car {
public void drive() {
System.out.println("Porsche driving Fast ");
}
public void drive(String s) {
System.out.println("Porsche driving " + s);
}
}

Notice that the Porsche class has both overloaded and overridden the drive() method.

Tip: Don’t be fooled by a method that’s overloaded but not overridden by a subclass. It’s perfectly legal to do the following:
public class Car {
void drive() { }
}
class Ferrari extends Car{
void drive(String s) { }
}

The Ferrari class has two drive() methods: the no-arg version it inherits from Car (and does not override), and the overloaded drive(String s) defined in the Ferrari class. Code with a reference to a Car can invoke only the no-arg version, but code with a reference to a Ferrari can invoke either of the overloaded versions.


Differences between Overloaded and Overridden Methods:

  Overloaded Methods Overridden Methods
Arguments Must Change Must Not Change
Return Type Can Change Cannot Change (Except for Covariant Returns)
Access Can Change Cannot Change to more restrictive (Can be less restrictive)
Invocation Reference type determines which overloaded version (based on declared argument types) is selected. Happens at compile time. The actual method that’s invoked is still a virtual method invocation that happens at runtime, but the compiler will already know the signature of the method to be invoked. So at runtime, the argument match will already have been nailed down, just not the class in which the method lives. Object type (in other words, the type of the actual instance on the heap) determines which method is selected. Happens at runtime.
Constructor Overloading is actually another topic that would be a part of this polymorphism/overloading discussion but we will be covering that as part of one of the subsequent chapters.

Previous Chapter: Chapter 7: Object Oriented Concepts - Inheritance

Next Chapter: Chapter 9: Reference Variable Casting

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

Tuesday, January 4, 2011

Chapter 6: Object Oriented Concepts – Encapsulation

One of the key strengths of Java is that it is object oriented. In other words, everything in Java is an object. You might have heard me say this in the previous chapters and for sure I will say that at times in the future chapters as well because everything in Java is an object. There are a few important features/characteristics that Java exhibits by virtue of being object oriented. We will be covering them one by one in the following chapters.

Encapsulation:

Imagine that we both work for the same project and first you wrote the code for a class, and then I used your class in my program. Later on, you didn’t like the way the class behaved, because some of its instance variables were being set (by me from my code) to values you hadn’t anticipated. Their code brought out errors in your code. (Relax, I wont do that, dont worry.) Since, it is a Java program, so you should be able just to ship out a newer version of the class, which I could replace in my programs without changing any of my own code.

The above scenario highlights two of the promises or rather i should say benefits of Object Orientation (OO): flexibility and maintainability. But these benefits will not come automatically. You have to do something. You have to write your classes and code in a way that supports flexibility and maintainability. Just because Java supports OO concepts, it cannot write code for you. Can it?? For example, imagine if you made your class with public instance variables, and those other programmers were setting the instance variables directly, as the following code demonstrates:

public class BadExample {
public int size;
public int weight;
...
}
public class AnotherBadExample {
public static void main (String [] args) {
BadExample b = new BadExample ();
b.size = -5; // Legal but bad!!
}
}

Now go back the scenario we spoke about a paragraph ago. BadExample is your class and AnotherBadExample is my code. I have modified one of your variables in a way that it helps my code logic but that totally alters the way your class works. Now you are in trouble. How are you going to change your class in such a way that no one can alter your values directly (like what i have done in my code)? Your only choice is to write a method say setSize(int newVal) inside your class and then change the access modifier of the variable size to say, private. This will ensure that you handle instances when someone is trying to set a value to the size variable that you dont want and at the same time ensure that no one can access the size variable directly and mess with your code.

But, unfortunately, by doing that, you have broken my code. If I try to compile my AnotherBadExample class, i will get errors because the size variable is no longer visible for me.

How can we address this situation now? The best way is: not write such code where public variables are available for anyone and everyone to modify.


The ability to make changes in your code without breaking the code of all others who use your code is a key benefit of encapsulation. You should always hide implementation details. To elaborate, you must always have your variables as private and then have a set of public methods that others can use to access your variables. Since the methods are public anyone can access them, but since they are in your class you can ensure that the code works the way that is best for you. So in a situation that you want to alter your code, all you have to do is modify your methods. No one gets hurt because i am just using your method names in my code and the code inside your method doesnt bother me much.

If you want maintainability, flexibility, and extensibility (and I guess, you do), your design must include encapsulation. How do you do that?
• Keep instance variables protected (with an access modifier, mostly private).
• Make public accessor methods, and force calling code to use those methods rather than directly accessing the instance variable.
• For the methods, use the JavaBeans naming convention of set and get.

We call the access methods getters and setters although some prefer the fancier terms accessors and mutators. (Personally, I will be using the terms getters and setters) Regardless of what you want to call them, they’re methods that other programmers must go through in order to access your instance variables. They look simple, and you’ve probably been using them forever if you have been writing java code:

public class GoodExample {
// protect the instance variable only an instance of your class can access it
private int size;
// Provide public getters and setters
public int getSize() {
return size;
}
public void setSize(int newSize) {
size = newSize;
}
}

You are now probably mumbling, what benefit is it to have methods that do nothing and just set or get values. I would rather have a public variable. If you did that go to the first paragraph under Encapsulation and re-read the whole thing. And if you did not do that but are asking me, where is the validation code that we are supposed to have in the setSize() method to ensure no one modifies it to invalid values, my friend this is just an example class. I leave you to ponder about how the implementation needs to be. Atleast you wont end up on the receiving side of unexpected shocks because of someone like me coding along with you or worse !!!

Tip: In the exam watch out for code that appears to be asking about the behavior of a method when the problem is actually lack of encapsulation. Check out the below example:
class Test {
public int left = 9;
public int right = 3;
public void setLeft(int leftNum) {
left = leftNum;
right = leftNum/3;
}
// lots of complex test code here
}

Now let us say I ask you this question: Will the value of the variable right always be 1/3rd of the value in left? It sure looks that way doesnt it? And if you said Yes, the answer is No. See these variables they are public and they are not encapsulated like the example just a paragraph above. So a novice programmer like me could always set the value directly inside my code to spoil the party.

You must be cautious in order to spot such questions that are fairly easy and straightforward but confusing if you are in a hurry to finish the question.

Previous Chapter: Self Test - Chapters 1 to 5

Next Chapter: Chapter 7: Object Oriented Concepts - Inheritance
© 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