95.105/145 - Introduction to Programming
Fall 2001

 9  Inheritance, Type-Casting and Interfaces


What's in This Set of Notes ?


 9.1 Class Hierarchies and Inheritance

You have heard the term inheritance before.  In English, Inheritance is essentially: “getting something for free” (when someone dies).   Inheritance is the act of getting (for free) shared state and behaviour from more general types of objects.

A subclass (child) inherits this from all of its superclasses (ancestors):

This means that the subclass: Classes that share common attributes can be grouped together.  The grouping of these classes forms a tree called a class hierarchy.
This class hierarchy specifies the "IS A" (or "is kind of") relationship among the classes.

Inheritance:

Each class is a subclass of some other class which is called the superclass.
The direct superclass is the class right “above” it.

Here, Snake, and Lizard are subclasses of Reptile (which merely means that they are specializations).   Also Whale and Dog are subclasses of Mammal.  All of the classes are subclasses of Animal (except Animal itself).  Animal is a superclass of all the classes below it, and Mammal is a superclass of Whale and Dog.   As we can see, we can go even deeper in the hierarchy by creating subclasses of Lizard.

A subclass:

A superclass: direct superclass: Some languages allow Multiple Inheritance: At the very top of the hierarchy is the class called Object.  That means, all classes in java are subclasses of object!!!!

We often make subclasses of our own objects:

Here are a few more hierarchies:

Be careful not to use a “has a” relationship !!!


 

To create a subclass of another class, use the extends keyword in the class definition.
 
public class extends B {
   ...
}

If the extends keyword is not used, it is assumed that the class extends Object.

How do we know how deep to make the tree ?   Most of the time, any “is a” relationship should certainly result in subclassing.  OO code usually involves a lot of small classes as opposed to a few large ones.  Often, the code (i.e., hierarchies) ends up being  rearranged over time.  So, we often make mistakes the first time around :).

It is not always easy to chose a hierarchy ... it depends on the application.

Students in a university (may be represented many different ways...here are just 3 possibilities):

How do we know which one to use ?   It will depend on the state and behaviour.   If we find that the main differences in behaviour are between full time and part time students, then we may choose the top hierarchy (e.g., fee payments).   If however the main differences are between grad/undergrad, (e.g., privledges, requirements, exam styles etc..) then we may choose the middle hierarchy.    The bottom hierarchy further distinguishes between full/part time grads/undergrads.   So...the answer is...we often don't know which hierahcy to pick until after we get started with the code :).

Consider making an object to represent Employees in a company which maintains: name, address, phoneNumber and employeeNumber

We may make a single class for this:

Now what if we want to distinguish between regular Employees and Managers ?

We must think of what is different between these classes with respect to state and behaviour.

Managers may have

In these situations, Managers should be represented as a “kind of” Employee:

What if we wanted to represent Customers as well ?   Customers probably have state like this:  name, address and phoneNumber.   This state information is also used by Employees

Idea:
We could just make Employee objects and set their employeeNumber to something like -1 to indicate that it is not an Employee, but in fact a Customer.

Employee jim = new Employee(“Jim”, “13 Elm St.”, “555-2394”, 762389);
Employee bill = new Employee(“Jim”, “13 Elm St.”, “555-2394”, -1);
That’s a HORRIBLE idea!   It actually undoes the whole concept of OOP !

We MUST have a

Neither of the following two hierarchies will work since:

Perhaps we can name the Customer class Person.  So, Customers are just Person objects:

This is a good solution as long as:

If there is indeed different behaviour or state that is unique to Customers, then we must “abstract out” even further and make a Customer class:

So in the end, the state stored in each class is:

We do the same kind of “thinking” to abstract out the common behaviours and place them in the appropriate class.


 9.2 Abstraction: Abstract Classes & Methods

An Abstract Class:

A Concrete Class: Why would we EVER want to create an Abstract class if we cannot make instances of it ? As we will see later, we can treat similar kinds of objects as something more abstract. We define an abstract class by using the abstract keyword in the class definition:
 
public abstract class BankAccount {
}

This class must have subclasses in order to be useful.
How do we know which classes to make abstract ?

Consider the following hierarchy: The Shape class is most likely abstract since we probably have no instances of shape.  Instead, a user must instantiate one of the subclasses.   If we only need Circles, Triangles, Rectangles and Squares, then all common state & behaviour for all these classes can be placed in Shape.

Maybe later we need to add more shapes.  What about a Cube or a Sphere or even a Tetrahedron ?  Well, we can merely add it as a subclass of Shape, but maybe we need to make a distinction between 2D and 3D objects.  We may want to abstract out even more (this is called abstraction):

Now we can put the state/behaviour that is common for 2D shapes in the TwoDimensionalShape class and that common to 3D shapes in ThreeDimensionalShape.    Note however, that we will never want to say:  new Shape(), new TwoDimensionalShape() etc..., so we make these Abstract.

Perhaps we need to abstract out more later with our objects as we add more shapes.  We may end up with something like this:

We may never have instances of Polygon or Polyhedron.  So these may become abstract classes.

Abstraction is the process we have just been applying to our hierarchy.   It allows us to extract the common features out of a class's subclasses.  For instance, a polygon may keep a bunch of vertices and line segments.  All Triangles, Rectangles and Squares will make use of these features and perhaps share the same drawing method.

Recall the Person/Employee/Manager example:

If the only people being used in this application are Customers, Employees and Managers, then we can make the Person class abstract.

If however, we had used the hierarchy in which Customers were just Person objects, then we CANNOT make the Person class abstract since Person objects represent Customers.

For BankAccounts, we may wish to make BankAccount, SavingsAccount and CheckingAccount all be abstract:

This forces the users of these classes to specify the most specific type of bank account required.
 

Abstract Methods:

In addition to having abstract classes, Java allows us to make abstract methods.   Only abstract classes can have abstract methods.  However, an abstract class DOES NOT have to have only abstract methods.

All subclasses inherit all of the visible methods from their superclasses, even if the superclasses are abstract, so inheritance works the same.

An abstract method is a method with no code.   It is defined using this format:
 
public abstract <returnType> <methodName>(...);

Notice the ; used at the end of the definition ... there are no { } characters.

Abstract methods have no code !!!!   Why would we want a method that has no code ?

We can make deposit(float amount) and withdraw(float amount) methods abstract in the BankAccount class.   Thus, all concrete subclasses must implement them:   SuperSavings, PowerSavings, BusinessChequing and PowerChequing.

Note that abstract classes SavingsAccount and ChequingAccount do NOT NEED TO implement the abstract methods in BankAccount.

Alternatively, we could write non-abstract methods deposit(float amount) and withdraw(float amount) in the BankAccount class and have the subclasses either use or override them.

Abstract classes are often used to specify some “standard” behaviour for use by its subclasses.

E.g. we can make a Loan class abstract and then specify behaviour that all Loan objects should have:

public abstract class Loan {
    public abstract float calculateMonthlyPayment(); //abstract method
    public abstract void makePayment(float amount); //abstract method
    public abstract void renew(); //abstract method
    public Client getClientInfo() { //non-abstract method
        ...
    }
    ....
}
Note that all concrete subclasses of Loan MUST implement the 3 abstract methods.

Here's another example.  Consider the Animal class as shown at the top of these notes as being an abstract class with some abstract methods and some non-abstract methods as follows:

public abstract class Animal {

    public void eat(Food someFood) {
        putInMouth(someFood);
        chew(someFood);
        swallow(someFood);
    }
    public abstract void putInMouth(Food someFood);
    public abstract void chew(Food someFood);
    public abstract void swallow(Food someFood);

    public void sleep(int minutes) {
        ....
    }
    public abstract void poop();

    ...
}

In this code, the putInMouth(), chew(), swallow() and poop() methods are all declared as abstract.  Note that the code is not given.   By doing this, we are FORCING ALL subclasses of Animal to implement these methods.   The compiler will complain if the methods are not implemented.

That means, the Reptile and Mammal classes must implement these methods.   Note that some methods (such as eat()) may not be abstract.

So by writing an abstract method, we force all subclasses to adhere to some "standard".  As we can see, the eat method requires the putInMouth(), chew() and swallow() methods to be written in the subclasses.  That is, we provide a guarantee that the subclasses will implement all of the required methods.


 9.3 Method Lookup and Overriding


The amount of inheritance an object receives is based on its position in the hierarchy.   An object inherits the state and behaviour from all the superclasses up the tree along the path to Object:

Since Object is at the top of the hierarchy, every class inherits from Object.
What kind of neat behaviours do we inherit from Object ?    toString(), equals(), hashcode(), clone()

To cause inheritance in our own classes, we merely make our class to be a subclass of the class we want to inherit from.

Consider the inheritance in this example:

 
public class Person  {
  public String name;
  public String getName(){
     return name; }
}
public class Employee  extends Person  {
  public int employeeNumber;
  public int getEmployeeNumber(){
       return employeeNumber; }
}
public class Manager  extends Employee  { 
   public Vector responsibilities;
   public Vector getResponsibilities(){ 
       return responsibilities; }
}
Employee inherits name and getName() from Person.
Manager inherits name and getName() from Person as well as employeeNumber and getEmployeeNumber() from Employee.

Both Employee and Manager objects can use the fields and methods of their superclass as if it was defined in their own class:

Employee jim = new Employee();
jim.name = “Jim”;
jim.employeeNumber = 123456;
System.out.println(jim.getName());

Manager betty = new Manager();
betty.name = “Betty”;
betty.employeeNumber = 543469;
betty.responsibilites.add(“Internet project”);
System.out.println(betty.getName());
System.out.println(betty.getEmployeeNumber());

A subclass cannot, however, access private methods or private fields from its superclasses:
public class B  {
    public int a = 10;
    private int b = 20;
    protected int c = 30;
    public int getB()  { return b; }
}
public class  A extends B  {
    public int d;
    public void tryVariables()  {
        System.out.println(a); //access allowed
        System.out.println(b); //access NOT allowed
        System.out.println(getB()); //can get private variable value through this public method
        System.out.println(c); //access allowed
    }
}
Note: 
  • Even though a class cannot access the private fields of its superclasses, it still inherits these fields as part of its own state.
  • We can also use the protected keyword for fields:
    • protected fields can be accessed by a class, its subclasses and any classes in the same package.   So it is a kind of "semi-private" access.

 

Overriding:

Through inheritance, a class inherits all the methods of its superclasses.   That means, a subclass can use any methods of its superclasses as if they were its own.  It may be the case that a subclass does not want to inherit some methods from its super class.  If this is the case, then the subclass can choose to ignore the superclass method by making its own method with the same name (and same parameter list) that does something else (perhaps nothing).

A method in a class is overridden by one of its subclasses if the subclass implements the method using the exact same signature.

Overriding is used when:

 
(e.g., assume that the SuperSavings account cannot be withdrawn from)
  • Write withdraw(float amount) in BankAccount class as usual.
  • Don’t write withdraw(float amount) in SavingsAccount
    • allow it to be inherited from BankAccount 
  • Override the method in SuperSavingsAccount:
      public void withdraw(float amount)  {
        // Do Nothing
      }
The final/protected keywords:

If a method is declared as final, it CANNOT be overridden, the compiler will stop you:

public final void withdraw(float amount) {
    ...
}
Why would we want to do this ?   Well...perhaps the behaviour defined in the method is very critical and overriding this behaviour improperly may cause problems with the rest of the program.

If a class is declared as final, it CANNOT have subclasses:

public final class Manager {
    ...
}
Why would we want to do this ?   Well...perhaps the class has very weird code that the author does not want you to inherit...maybe because it is too complicated and may easily be miss-used.     Many of the java classes (e.g., Vector) are declared final which means that we cannot make a subclass of them....its a kind of security issue to prevent us from "messing up" the design and intentional usage of those classes.

If a method is declared as protected, it can be accessed, from this class or its subclasses:

protected void withdraw(float amount) {
    ...
}


Method Look-Up:

When a message (method) is sent to an instance, Java must look up the method in the class hierarchy and then evaluate it.  It is important to understand how Java “looks up” methods when we send messages to objects.   Assume that we send a message M() to an instance of class D:

Method lookup for all instance methods works as follows:

If not found at all during this search up to the Object class, the compiler will catch this and inform you that it can't find the method M() for the object you are trying to sending it to:

The use of super merely specifies where the method lookup should begin the search.   If for example, we are in a method belonging to class D that calls super.M() , the lookup for M() will start in class C first:

The super keyword is also used in constructors to call a constructor in the superclass.   Java automatically calls the superclass’ default constructor if you do not specify a call yourself.   If you do want to call a superclass constructor, it MUST be the first line of your constructor code.

public BankAccount(String own, float bal) {
    owner = own;
    balance = bal;
}
public SavingsAccount(String own){
    super(own, 0.0f); //Calls above constructor, otherwise the default
                  //constructor in BankAccount would have been called.

}

Java does lookup for static methods differently

Example

If we would like to implement a university system we might come up with the following hierarchy showing the different types of people:
 

Person
Employee
Professor
Secretary
Student
FullTimeStudent
PartTimeStudent
(name, phone#, address)

(employee#, workPhone#)

(courses, office #)
(workload, schedule)

(student#, courses, gpa)

(major)
(workPhone#)

From this example we can see that there are different specializations of people but each of these special people share some common attributes (name, phone# and address).  This does not mean that they all have the same name, address or phone#; it merely means that they all have this type of information associated with them.   A specialization of the Person object is the Employee class in which all employees have information pertaining to their employee number and work telephone number.  Because the employees are specializations of people, Employee is made to be a subclass of Person.  This allows Employee instances to inherit the properties (attributes) of Person objects.  The same argument applies to all the other subclasses above.

Thus, we only need to make get and set methods for name, phone# and address in the Person class.  All other subclasses will inherit these methods which means that they will all automatically understand the messages   getName(), setName(), getPhoneNumber(), setPhoneNumber() etc... This is very useful since it saves us from having to repeatedly type duplicate methods.

In our university example above, we would have declarations (each in a separate file of course) that look something like this:

Consider the toString()method for the Person, Employee, Professor and Student classes. Perhaps we'd like to return strings that look something like this for the different toString() methods:

"Person
  NAME:       Jim Class
  ADDRESS:    1445 Porter St.
  PHONE #:    845-3232"

"Employee
  NAME:       Rob Banks
  ADDRESS:    789 ScotiaBank Road.
  PHONE #:    899-2332
  EMPLOYEE #: 88765
  WORK #:     555-2433"

"Professor
  NAME:       Guy Smart
  EMPLOYEE #: 65445
  WORK #:     232-3415
  OFFICE #:   5240 PA"

"Secretary
  NAME:       Earl E. Bird
  ADDRESS:    12 Knowhere Cres.
  PHONE #:    443-7854
  EMPLOYEE #: 76845
  WORK #:     444-3243"

"Student
  NAME:       May I. Passplease
  ADDRESS:    5567 Java Drive
  PHONE #:    732-8923
  STUDENT #:  156753"

Also note that not all information is shown using this method.  For example, the courses were not displayed for Professors or Students since there may be too many and a toString() method should never return a big string.  We can clearly write a toString() method for each class that does what we want.  However, this would be wasteful.  Let's try to save ourselves from writing a lot of code.  We'll try to "share" code among classes by making use of inheritance and the super keyword.

First, we notice that all classes show the name.  This should definitely be done in the Person class since all others are subclasses and can inherit the code.  Next, we see that all classes (except Professor) also show the phone number and address.  I guess Professors do not want to show everybody this information.  Thus, we'll allow all subclasses to display this information and we'll have to do something different for the Professor class.  Lets write the toString() method for the Person  class:

However, since subclasses are going to inherit from this method, they will want to make sure that the word "Person" is replaced accordingly with the name of the class.  We can do this by making use of  this.getClass().getName() so that all subclasses will put their own class name in here. Now what else is common within the remaining classes ?  We notice that all Employees (also Professors and Secretaries) show the employee number and work number.  Therefore, this can all be done in the Employee class.  Of course, now to make sure that the name, address and phone number is visible, we must use the superclass method first: Note the use of super.toString().  This allows us to inherit what the superclass did as well as add the information for this class.  Now the Secretary class does not even need a toString() method since it already inherits from Employee and this is exactly what we want to see.  The Professor class however, will have problems.  We cannot merely inherit from Employee because the Employee method inherits from Person (which displays the phone number and address).

Therefore, we can do this one without inheritance by completely overriding the Employee method:

Too bad though since we have now some duplicate code.   If only there was a way to make use of "some" of the code in the Person class, but not all of it.   If we change the toString() method in the Person class, then this may affect the toString() in Employee class.  We must be careful.

We know that sometimes (i.e., for professors) we don't want to see the address and phone number, whereas other times (i.e., for employees and persons) we do need to see it.   We can make a boolean version of the Person class's toString() method as follows:

public String toString(boolean showAddresses) {
    String s = getClass().getName() + "\n" +
          "  NAME:       " + getName() + "\n";
    if (showAddresses)
        s += "  ADDRESS:    " + getAddress() + "\n" +
             "  PHONE #:    " + getPhoneNumer());
    return s;
}
But wait!   This is no longer overriding the toString() method in Object, so printing out a Person does not work properly anymore!   We can fix this by having the toString() method call this one:
public String toString() {
    return toString(true);
}
Now, we can have the Employee toString() method call the boolean version in Person with true and professors call it with false:
//This is the toString method for the Employee class
public String toString() {
    return(super.toString(true) + "\n" +
            "  EMPLOYEE #: " + getEmployeeNumber() + "\n" +
            "  WORK #:     " + getWorkNumer());
}

 //This is the toString method for the Professor class
public String toString() {
    return(super.toString(false) + "\n" +
            "  EMPLOYEE #: " + getEmployeeNumber() + "\n" +
            "  WORK #:     " + getWorkNumer() + "\n" +
            "  OFFICE# :   " + getOfficeNumber() + "\n");
}

The Professor method calls the toString(boolean) method all the way up in Person.   In fact, java looks for it in the Employee class, does not find it and then looks in Person....and there it finds it.    The code works, but we see that there is duplication in the Employee and Professor methods.   Can we fix this ?   Sure!   Just have another boolean version of the toString() method in the Employee class:
//This is the toString method for the Employee class
public String toString(boolean showAddresses) {
    return(super.toString(showAddresses) + "\n" +
            "  EMPLOYEE #: " + getEmployeeNumber() + "\n" +
            "  WORK #:     " + getWorkNumer());
}
//This is the toString method for the Employee class
public String toString() {
    return(toString(true));
}

 //This is the toString method for the Professor class
public String toString() {
    return(super.toString(false) + "\n" +
            "  OFFICE# :   " + getOfficeNumber());
}

Note that the Professor class does not have a special toString(boolean) method and so we don't need to write super since java will automatically go and look in the superclass when it does not find this method:
 //This is the toString method for the Professor class
public String toString() {
    return(toString(false) + "\n" +
            "  OFFICE# :   " + getOfficeNumber());
}
Now the Student class merely inherits from Person and also displays the student number. As for the subclasses of Student, they appear the same and hence they both inherit from Student as Secretary inherited from Employee.  You should now see that inheritance is very useful since it allows objects to share code which cuts down on the amount of time needed to create applications.
 

Inheritance with Constructors:

How do we initialize (write constructors for) the classes in our university example ?  See below.  The get and set methods are not shown.



 9.4 Type-Casting, Polymorphism and Double-Dispatching


We have already seen type-casting with primitives.  Type-casting with objects is a little more complicated.

Many classes in Java make use of automatic type-casting, so we must understand:

For primitives, type-casting is the process of converting a value from one form to another:
(int)871.34354;   // results in 871
(char)65;        // results in ‘A’
(long)453;        // results in 453L
For objects, type casting does not convert, but merely causes the object to be “treated” more generally.
When objects are casted: To understand type-casting, look at these examples: One of the main advantages of type-casting is that it allows for polymorphism: We have already seen some cases of polymorphism: A BIG advantage of polymorphism is that by treating objects more generally (i.e., type-casting to superclasses) we just need to understand a few commonly understood messages that all these objects understand.  For example, we can: Type-casting makes use of polymorphism because all objects that can be type-casted to the same type will all respond to the same messages.   The code is therefore shorter & easier to understand :)

Consider the following hierarchy:

If we are given one of these shapes, we may wish to draw it or perhaps ask how many sides it has.  However, we may not know exactly what shape is given to us, so we would have to make a check.  Perhaps a bunch of if statements could be used:

aString = aShape.getClass().getName();
if (aString.equals(“Circle”))
    aShape.drawCircle();
if (aString.equals(“Triangle”))
    aShape.drawTriangle();
if (aString.equals(“Rectangle”))
    aShape.drawRectangle();
or even better:
if (aShape instanceof Circle)
    aShape.drawCircle();
if (aShape instanceof Triangle)
    aShape.drawTriangle();
if (aShape instanceof Rectangle)
    aShape.drawRectangle();
However, looking at the code, it is clear that all we want to do is draw the shape.  The shape must be drawn differently according to the type of shape it actually is.  In the code above, we have three different methods for drawing the shape and we are calling the appropriate one according to the type of shape.

There is a better way to write the code.  We could have a draw() method for each of the three shape classes.  Having the same method name (and signature) for different methods of multiple classes is called Polymorphism.

Why do we want this ?  Well, replace the method names in the code:

Clearly, we do not even need the if statements anymore.  We can just write: Wow!!! What a reduction in code!!!

There are many advantages to using polymorphism:

We have seen polymorphism already.   Here are some examples: Many objects have these methods.  It should be pointed out that if a method is inherited, it does not mean that polymorphism is happenning.  In fact, this is NOT an example of polymorphism.  In order to have polymorphism, there must be more than one method with the same name and signature.  An inherited method is NOT a different method.

There are certain rules for type-casting objects.   Objects may ONLY be type-casted to:

Attempts to type-cast to anything else will generate a  ClassCastException

Managers may be type-casted to Employee, Person or Object but not to Customer, Company or Car.  Some of these restrictions make sense, after all, why would we treat an Manager as a Company or a Car ?

Manager   man;
Employee  emp;
man = new Manager();
man.getName();
man.getEmployeeNumber();
man.getSalary();
emp = (Employee)man; // emp is actually pointing to a Manager object
emp.getName(); //Can use this methods since it is also defined in Person
emp.getEmployeeNumber(); //Can use this methods since it is also defined for Employee
emp.getSalary(); // emp cannot respond to Manager methods anymore
Explicit type-casting is not always required.   An object may be automatically type-casted when it:
Manager man = new Manager();
Employee  emp;
emp = man;  // automatic ... ame as saying emp = (Employee)man;
  • is sent as a parameter to a method
  • Manager man = new Manager();
    aCompany.doStandardHiringProcess(man); //Passed in as a Manager object

    public void doStandardHiringProcess(Employee emp) {
       ... //emp is type-casted to Employee upon entering this method.

    }

    REMEMBER:  Java ALWAYS knows the “original” type of every object...and this NEVER changes.
     
    IMPORTANT:   You are only allowed to use methods which are defined in the class being type-casted to.   However, when methods are called, lookup begins in the original class.

    Here is another example:

    Professor   prof;
    Employee  anEmployee;

    prof = new Professor();
    anEmployee = (Employee)prof; //From now on, treat the Professor as an Employee

    anEmployee.computeSalary();    //This will work
    anEmployee.hasTenure();       //This won't work since hasTenure() is only defined for Professors

    Note that we have type-casted the Professor to be an Employee object.   From that point onwards, we may only send Employee methods to the object.   Make sure to keep in mind that type-casting does NOT do any kind of conversion.   In fact, the anEmployee variable in the above example actually points to a Professor object.   That is, the type casting does not change the fact that the object is a Professor object.  The type-casting process for objects merely informs the compiler that from now on, the object is to be treated as an Employee.   In fact, we can always type-cast back again:
    Professor  aProf;
    aProf = (Professor)anEmployee; //From now on, treat the object again as a professor

    aProf.computeSalary();       //This will still work
    aProf.hasTenure();        //Works now

    So...an object may be type-casted back again at any time.  Look again at the Manager example:
    Manager   man = new Manager();
    Employee  emp = (Employee)man;
    emp.getName();
    emp.getEmployeeNumber();
    ((Manager)emp).getSalary();
    Type-casting may occur up and down the hierarchy along the path from the original type of the object to the Object class:

    How does method lookup occur for type-caseted objects ?
     
    For instance methods, method lookup ALWAYS begins 
    in the class of the original object.   Lookup then proceeds 
    as normal up the hierarchy.
    Manager   man = new Manager();
    Employee  emp1 = new Employee();
    Employee  emp2 = (Employee)man;
    emp1.computePay(); //in Employee

    man.computePay(); //in Manager
    emp2.computePay(); //in Manager

    For static methods, lookup is done at compile time, and so 
    Java always begins in the class of the defined variable.
    Manager   man = new Manager();
    Employee  emp1 = new Employee();
    Employee  emp2 = (Employee)man;

    Manager.expenseAllowance(); //in Manager
    man.expenseAllowance(); //in Manager

    Employee.expenseAllowance(); //in Employee
    emp1.expenseAllowance(); //in Employee
    emp2.expenseAllowance(); //in Employee!!!

    Many Java methods work with arbitrary objects:  e.g., Collections can hold any kind of objects

    Many of these methods take Objects as parameters:

    public boolean equals(Object obj) {...}
    public void add(Object obj) {...}
    In these cases, any object can be passed into the method and the object is automatically type-casted to type Object.   Thus, inside the method, only messages that Object understands can be sent to the incoming obj.

    As we have already seen, type-casting is also necessary when extracting items from a Collection:

    Vector employees = getEmployees();
    for (int i=0; i<employees.size(); i++) {
       Employee emp = (Employee)employees.get(i);
       emp.doSomething();
    }
    We must type-cast here because both of these are true: Objects define the following comonly used methods:
    public Class getClass();
    public String toString();
    public boolean equals(Object obj);
    public void clone();
    public int hashCode();
    Every object inherits these methods from object.   The last 4 of these are often overridden.

    Double-Dispatching:

    Lets look back again at our shape-drawing example.   Consider now a Pen object which is capable of drawing shapes.  We would like to use code that looks something like this:

    aPen.draw(aCircle);
    aPen.draw(aTriangle);
    aPen.draw(aRectangle);
    However, this is not so straight forward.   We would have to define a draw method in the Pen class for each kind of shape in order to satisfy the compiler with regards to the type of the parameter:
    public void draw(Circle aCircle) {
         // Do the drawing
    }
    public void draw(Triangle aTriangle) {
         // Do the drawing
    }
    public void draw(Rectangle aRectangle) {
         // Do the drawing
    }
    Well, since the drawing code is likely different for all 3 shapes...then don't we need 3 different methods anyway ?  YES.   However, the way the code is arranged, we have to write all the draw methods in the Pen class.   So, if we later want to add some more Shapes (such as polygons, ellipses, parallelograms etc...), we would have to go into the Pen class and add a draw method for each Shape.   This is BAD...because the Pen class is highly dependent on the different kinds of Shape objects.   We would like a way of separating the Pen class completely, so that we don;t have to come back to it later and add more draw methods.

    Well, in fact, we can indeed declare a single method as long as all the Shapes inherit from a common superclass (or implement a common interface as we'll see later).  We are lucky here since all of our shapes are subclasses of the Shape class.  So, we can write one method that takes a Shape parameter:

    public void draw(Shape anyShape) {
         // Do the drawing
    }
    This is actually a VERY powerful concept.   It prevents us from having to write a method for every kind of parameter object!!   Now we simply write one draw method that handles all shapes :).

    Wait a minute!!!  We still have a minor problem though.   What does the code look like inside the method ?

    public void draw(Shape anyShape) {
    if (anyShape instanceof Circle)
        // Do the drawing for circles
    if (anyShape instanceof Triangle)
        // Do the drawing for triangles
    if (anyShape instanceof Rectangle)
        // Do the drawing for rectangles
    }
    That is, we seem to still have to decide how to draw the different Shapes.   So then when new Shapes are added, we still need to come into the Pen class and make changes :(.    We can correct this problem by shifting the drawing responsibility to the Shapes themselves, as opposed to being a Pen responsibility.   This "shifting" (or flipping) of responsibility is called double dispatching (the name implies that a message is "dispatched" twice in order to be accomplished)

    We perform double-dispatching by making a method in each of the specific Shape classes that allows the shape to draw itself using a given Pen object:

    //This method should be in the Circle class
    public void drawWith(Pen  aPen) {
         // Do the drawing with the given pen
    }
    //This method should be in the Triangle class
    public void drawWith(Pen  aPen) {
         // Do the drawing with the given pen
    }
    //This method should be in the Rectangle class
    public void drawWith(Pen  aPen) {
         // Do the drawing with the given pen
    }
    Now, we reduce the code in the Pen class to the following:
    public void draw(Shape anyShape) {
         anyShape.drawWith(this);
    }
    So ... when we ask the Pen to draw the Shape,  it kinda says: "No way! let the shape draw itself using me".   It represents a notion similar to the phrase  "passing the buck".   This is a very common technique which is used in OO programming and it helps to reduce/simplify the code.   Polymorphism makes it all work.

    NOTE:   In order for this to compile, you must have a drawWith(Pen   p) method declared in class Shape since it is declared as abstract.


    Example:

    Here is a more in-depth example of inheritance with type-casting.  Consider the following classes:
     
    public class Person {
      String         name;

      static int     lifeSpan = 60;
      static double  ageFactor = 1.0;

      public Person() {

        name = "";
      }
      public Person(String aName) {
        name = aName;
      }
      public String getName() { return name; }
      public void setName(String aName) { name = aName; }
      public String toString() {
        return("Hello, my name is " + name);
      }
      public String talk() {
        return("I have nothing to say.");
      }
      public String walk() {
        return("I have nowhere to go.");
      }
      public static double lifeSpan() {
        return(lifeSpan * ageFactor);
      }
    }
    public class Boy extends Person {
      static double   ageFactor = 1.1;

      public String talk() {

        return(super.talk() + " ... but I hate history class.");
      }
      public String walk() {
        return("I am now walking");
      }
    }
    public class Girl extends Person {
      static double   ageFactor = 1.3;

      public Girl(String aName) {

        name = "Ms." + aName;
      }
      public String talk() {
        return("Hello! " + jump());
      }
      public String jump() {
        return("I am jumping.");
      }
      public static double lifeSpan() {
        return(lifeSpan * ageFactor);
      }
    }

    Now try to determine the output of the following code:

    Here is the output (can you explain it ?):
     
    Hello, my name is Fred
    I have nothing to say.
    I have nowhere to go.

    Hello, my name is 
    I have nothing to say. ... but I hate history class.
    I am now walking

    Hello, my name is Ms.Betty
    Hello! I am jumping.
    I have nowhere to go.

    Hello, my name is 
    I have nothing to say. ... but I hate history class.
    I am now walking

    Hello, my name is Ms.Betty
    Hello! I am jumping.
    I have nowhere to go.

    60.0
    60.0
    78.0

    java.lang.ClassCastException: Person
     at TestPeople.main(TestPeople.java:41)

    Hey!  The lifespan() method did not work the way that we expected.  That's because for class methods, method look-up occurs at compile time.  The lifeSpan() method in the Person class is used by both the Boy and Person classes.   In this case, since the method is static and declared in the Person class, the ageFactor from the Person class is used.   However, the Girl class has its own lifeSpan() method, so the ageFactor within the Girl class is used in that case.   Weird eh ?
     


     9.5 Interfaces


    Besides polymorphism, there is another concept that allows the programmer to understand a class and remember its functionality.  This is called an interface.

    An Interface represents

    How does having an interface help us ? Like classes, they are types and are defined in their own .java files.
    Unlike classes, you cannot make instances of an interface.

    Interfaces are like abstract classes in that they define common behaviour between a set of classes.
    For example, an insurance company may define an Insurable interface and have different kinds of objects implement the interface.

    Defining the interface, involves determining the common behaviour for all implementors of the interface.

    Unlike abstract classes however, interfaces allow us to specify common behaviour between seemingly unrelated objects:

    We use the interface keyword instead of the class keyword when defining an interface.
     
    public interface interfaceName {
        // Method specifications
    }

    Defining it is similar to defining an abstract class with no state and only abstract methods:

    public interface Insurable {
        public int getPolicyNumber();
        public int getCoverageAmount();
        public double calculatePremium();
        public Date getExpiryDate();
    }
    Once this is saved and compiled, classes may then implement and use the interface using the implements keyword in their definition:
     
    public class className implements interfaceName {
        /* Bodies for the interface methods */
        /* Own data and methods. */
    }

    Classes that implement the interface must implement ALL of the interface methods:

    public class Car implements Insurable {
        public int getPolicyNumber() {
            // write code here
        }
        public double calculatePremium() {
            // write code here
        }
        public Date getExpiryDate() {
            // write code here
        }
        public int getCoverageAmount() {
            // write code here
        }
    }
    Classes may implement more than one interface.

    To do this, just specify each in the class definition:

    public class Car implements Insurable, Drivable, Sellable {
       ....
    }
    Here, Car would have to implement ALL of the methods defined in each of the three interfaces.
    Here is another example:
    public class Vegetable extends Food implements  EdibleObject, ThrowableObject, CookableObject{
        ...
    }
    Like classes, interfaces can be organized in a hierarchy.

    Classes implementing an interface must implement its “super” interfaces as well.

    public interface DepreciatingInsurable extendsInsurable {
        public double computeFairMarketValue();
    }
    public interface FixedInsurable extends Insurable {
        public int getEvaluationPeriod();
    }
    Objects can also be type-casted to an interface type, provided that the class implements that interface.

    Car   jetta = new Car();
    Insurable  item = (Insurable)jetta;

    // We can now only send Insurable messages to item
    item.getPolicyNumber();
    item.calculatePremium();

    jetta.getMileage();       // This is OK
    item.getMileage();        // This is NOT OK
    ((Car)item).getMileage(); // This is OK too



    Another Example

    Consider typical operations on machines that move.  The interface on such objects may look as follows:

    This interface essentially defines what all MovableObjects should be able to do.  It is possible that they will do more, but this is the minimum.

    Now, consider a Plane.  It is a MovableObject and so it should implement this interface.  We can implement the interface for planes as follows:

    What about a Car, Train, Ship or even a Lawnmower ?  We can implement the MovableObject interface for each of these as well.

    Suppose we'd like to set up a handheld remote control for MovableObjects.  We can then treat all of the objects (Planes, Cars, Trains, etc...) as a single type of object ... a MovableObject.

    Notice that the remote control constructor is given an object that is of type MovableObject.  It could be a Plane, Car, Train, Ship, Lawnmower, ....  We can create remote controls for more than one class and each will operate correctly using its own implementation of the MovableObject interface. Note that we did something identical with the Shape class when we allowed different types of shapes to be passed as parameters to a draw method for the Pen class.

    Guess what ?   We can ALSO type-cast objects into their implemented interface:

    Plane            aPlane = new Plane();
    MovableObject    m = (MovableObject)aPlane;
    m.start();
    m.stop();
    m.getLastRepairDate(); //This won't work now
    So, everything works as it did in the Shape example.   Once we type-cast to an interface type, we can only send interface methods to the Plane.  Although it is still indeed a plane object, we cannot send Plane-specific methods to the object anymore (unless it is type-casted back to Plane).

    Interfaces vs. Abstract Classes:

    The use of abstract methods is very much like using interfaces.

    Recall the abstract methods in the Animal class:

    public abstract class Animal {
        public abstract void putInMouth(Food someFood);
        public abstract void chew(Food someFood);
        public abstract void swallow(Food someFood);
        public abstract void poop();

        public void sleep(int minutes) { ... }
        public void eat(Food someFood) { ... }
        ...
    }

    We could have defined the following interface:
    public interface AnimalInterface {
        public void putInMouth(Food someFood);
        public void chew(Food someFood);
        public void swallow(Food someFood);
        public void poop();
    }
    If we make the subclasses implement this interface, then this is another way of guaranteeing that they will have the required abstract behaviour.

    How are the two strategies similar ?   Both provide a guarantee that the methods will be implemented !
    So which way should we do it ?  Abstract classes with abstract methods or interfaces ?

    Interfaces are more flexible in that any class can implement the behaviour wheras with abstract classes, we only get to specify this common behaviour for classes that lie beneath Animal in the hierarchy.   Hence, the abstract class solution is more restrictive on the classes that will get this guarantee.   But Abstract classes DO allow non-abstract methods...