Chapter 5 Inheritance
1. Classes, Superclasses, and Subclasses
2. Objects: The Cosmic Superclass
3. Generic Array Lists
4. Objects wrappers and Autoboxing
5. Methods with a Variable Number of Parameters
6. Enumeration Classes
7. Reflection
8. Design Hints for Inheritance
The idea behind inheritance is that you can create new classes that are built on existing classes. When you inherit from an existing class, you reuse
(or inherit) its methods, and you can add new methods and fields to adapt your new class to new situations.
1. Classes, Superclasses, and Subclasses
Every manager is an employee
Here is how you define a Manager class that inherits from the Employee class
class Manager extends Employee { add methods and fields }
The keyword extends indicates that you are making a new class that derives from an existing class.
The existing class is called the superclass, base class, or parent class.
The new class is called the subclass, derived class, or child class.
When defining a subclass by extending its superclass, you only need to indicate the differences between the subclass and the superclass. When
designing classes, you place the most general methods into the superclass and more specialized methods in its subclasses. Factoring out common
functionality by moving it to a superclass is common in object-oriented programming.
However, some of the superclass methods are not appropriate for the Manager subclass. In particular, the getSalary method should return the sum
of the base salary and bonus. You need to supply a new method to override the superclass method:
public double getSalary() { return salary + bonus; // won't work }
However, that won’t work. The getSalary method of the Manager class has no direct access to the private fields of the superclass.
public double getSalary() { double baseSalary = super.getSalary(); return baseSalary + bonus; }
We need to indicate that we want to call the getSalary method of the Employee super-class, not the current class. You use the special keyword
super for this purpose. The call super.getSalary() calls the getSalary method of the Employee class
Finally, let us supply a constructor
1 public Manager(String n, double s, int year, int month, int day) 2 { 3 super(n, s, year, month, day); 4 bonus = 0; 5 }
Here, the keyword super has a different meaning. The instruction super(n, s, year, month, day); is shorthand for “call the constructor of the
Employee superclass with n, s, year, month, and day as parameters.”
The call using super must be the first statement in the constructor for the subclass.
1 //Employee.java 2 import java.util.*; 3 4 public class ManagerTest{ 5 public static void main(String[] args) { 6 7 Manager boss = new Manager("Boss",50000,1987,12,1); 8 boss.setBonus(5000); 9 10 Employee[] staff = new Employee[3]; 11 staff[0] = boss; 12 staff[1] = new Employee("lisi",30000,1989,10,1); 13 staff[2] = new Employee("wangwu",20000,1990,3,12); 14 15 // print out information about all Employee objects 16 for (Employee e : staff) 17 System.out.println("name=" + e.getName() + 18 ",salary=" + e.getSalary() + 19 ",hireDay=" + e.getHireDay()); 20 } 21 }
1 //Manager.java 2 public class Manager extends Employee{ 3 4 private double bonus; 5 6 public Manager(String n, double s, int year, int month, int day){ 7 super(n, s, year, month, day); 8 bonus = 0; 9 } 10 11 public double getSalary() 12 { 13 double baseSalary = super.getSalary(); 14 return baseSalary + bonus; 15 } 16 17 public void setBonus(double b) 18 { 19 bonus = b; 20 } 21 }
1 //ManagerTest.java 2 3 import java.util.*; 4 5 public class ManagerTest{ 6 public static void main(String[] args) { 7 8 Manager boss = new Manager("Boss",50000,1987,12,1); 9 boss.setBonus(5000); 10 11 Employee[] staff = new Employee[3]; 12 staff[0] = boss; 13 staff[1] = new Employee("lisi",30000,1989,10,1); 14 staff[2] = new Employee("wangwu",20000,1990,3,12); 15 16 // print out information about all Employee objects 17 for (Employee e : staff) 18 System.out.println("name=" + e.getName() + 19 ",salary=" + e.getSalary() + 20 ",hireDay=" + e.getHireDay()); 21 } 22 }
What is remarkable is that the call e.getSalary()
When e refers to an Employee object, then the call e.getSalary() calls the getSalary method of the Employee class. However, when e refers to a
Manager object, then the getSalary method of the Manager class is called instead. The virtual machine knows about the actual type of the object to
which e refers, and therefore can invoke the correct method.
The fact that an object variable(such as the variable e) can refer to multiple actual types is called polymorphism(多态性).
Automatically selecting the appropriate method at runtime is called dynamic binding
1.1 Polymorphism(多态性)
1 Employee e; 2 e = new Employee(. . .); // Employee object expected 3 e = new Manager(. . .); // OK, Manager can be used as well
In the Java programming language, object variables are polymorphic. A variable of type Employee can refer to an object of type Employee or to
an object of any subclass of the Employee class (such as Manager, Executive, Secretary, and so on).
1.2 Dynamic Blinding
At runtime, the call e.getSalary() is resolved as follows:
1. First, the virtual machine fetches the method table for the actual type of e. That may be the table for Employee, Manager, or another
subclass of Employee.
2. Then, the virtual machine looks up the defining class for the getSalary() signature. Now it knows which method to call.
3. Finally, the virtual machine calls the method.
1.3 Preventing Inheritance: Final Classes and Methods
Occasionally, you want to prevent someone from forming a subclass from one of your classes. Classes that cannot be extended are called final
classes, and you use the final modifier in the definition of the class to indicate this.
All methods in a final class are automatically final.
1.4 Casting
the process of forcing a conversion from one type to another is called casting.
double x = 3.405; int nx = (int) x;
To actually make a cast of an object reference, use a syntax similar to what you use for casting a numeric expression. Surround the target
class name with parentheses and place it before the object reference you want to cast. For example:
Manager boss = (Manager) staff[0];
There is only one reason why you would want to make a cast—to use an object in its full capacity after its actual type has been temporarily
forgotten
If you assign a subclass reference to a superclass variable, you are promising less, and the compiler will simply let you do it. If you assign a
super-class reference to a subclass variable, you are promising more. Then you must use a cast so that your promise can be checked at runtime.
it is good programming practice to find out whether a cast will succeed before attempting it. Simply use the instanceof operator. For example
1 if (staff[1] instanceof Manager) 2 { 3 boss = (Manager) staff[1]; 4 . . . 5 }
To sum up:
• You can cast only within an inheritance hierarchy.
• Use instanceof to check before casting from a superclass to a subclass.
Actually, converting the type of an object by performing a cast is not usually a good idea. In our example, you do not need to cast
an Employee object to a Manager object for most purposes. The getSalary method will work correctly on both objects of both
classes. The dynamic binding that makes polymorphism work locates the correct method automatically.
The only reason to make the cast is to use a method that is unique to managers, such as setBonus. If for some reason you find
yourself wanting to call setBonus on Employee objects, ask yourself whether this is an indication of a design flaw in the superclass.
It may make sense to redesign the superclass and add a setBonus method. Remember, it takes only one uncaught
ClassCastException to terminate your program. In general, it is best to minimize the use of casts and the instanceof operator.
1.5 Abstract Classes
Both students and employees have names, and introducing a common superclass lets us factor out the getName method to a higher level in
the inheritance hierarchy.
Now let’s add another method, getDescription, whose purpose is to return a brief description of the person, such as
an employee with a salary of $50,000.00 a student majoring in computer science
It is easy to implement this method for the Employee and Student classes. But what information can you provide in the Person class? The
Person class knows nothing about the person except the name. If you use the abstract keyword, you do not need to implement the method at all
1 abstract class Person 2 { 3 private String name; 4 public Person(String n) 5 { 6 name = n; 7 } 8 public abstract String getDescription(); 9 public String getName() 10 { 11 return name; 12 } 13 }
1.6 Protected Access
As you know, fields in a class are best tagged as private, and methods are usually tagged as public. Any features declared private won’t be
visible to other classes. As we said at the beginning of this chapter, this is also true for subclasses: A subclass cannot access the private fields
of its superclass.
There are times, however, when you want to restrict a method to subclasses only or, less commonly, to allow subclass methods to access
a superclass field. In that case, you declare a class feature as protected.
In practice, use protected fields with caution. Suppose your class is used by other programmers and you designed it with protected fields.
Unknown to you, other programmers may inherit classes from your class and start accessing your protected fields. In this case, you can no
longer change the implementation of your class without upsetting the other programmers. That is against the spirit of OOP, which encourages
data encapsulation.
Here is a summary of the four access modifiers in Java that control visibility:
1. Visible to the class only (private).
2. Visible to the world (public).
3. Visible to the package and all subclasses (protected).
4. Visible to the package—the (unfortunate) default. No modifiers are needed
2. Object: The Cosmic Superclass
The Object class is the ultimate ancestor—every class in Java extends Object. it is important to be familiar with the services provided by the Object
class.
2.1 The Eqauls method
The equals method in the Object class tests whether one object is considered equal to another.
2.2 The hashCode Method
P217