chapter7 inheritance
7.1 inheritance basic
(1)什么是继承?
继承就是从base class中得到的一个新类,该具有base class中的全部 method(private除外) + instance variable(private也可以继承)
比如:我们有两种员工,比如按小时计费和按月计费,其实这另个类都存在的变量是:name 和 hire date。同时很多方法也是重复的,因此我们可以创建一个类Employee ,作为base class。然后在此基础上创建 HourlyEmployee和 PartTimeHourlyEmployee。
--------------------------------------------------------------------------------------------------------------------------
(2 )A derived class?
A derived class:is a class defined by adding instancevariables and methods to an existing class(basic class)
A derived class is also called a subclass, in which case the base class is usually called a superclass
--------------------------------------------------------------------------------------------------------------------------
(3)继承的语法结构
比如,创建HourlyEmployee的时候,是从Employee中继承到了,则该类的heading如下:
public class HourlyEmployee extends Employee
~~继承得到的是什么呢?Employee中的所有变量和方法。但是我们不需要在HourlyEmployee的类中进行特殊说明或者声明。变量和方法同理。
For example, the class HourlyEmployee has all the instance variables and all the methods of the class Employee , but you do not mention them in the definition of HourlyEmployee.Every object of the class HourlyEmployee has instance variables called name and hireDate , but you do not specify the instance variable name or the instance variable hireDate in the definition of the class HourlyEmployee
比如:suppose you create a new object of the class HourlyEmployee as follows:
HourlyEmployee joe = new HourlyEmployee();
joe.setName("Josephine"); (可以直接使用setName(),不会报错)
--------------------------------------------------------------------------------------------------------------------------
代码: basic class --- employee
1 /**
2 Class Invariant: All objects have a name string and hire date.
3 A name string of "No name" indicates no real name specified yet.
4 A hire date of January 1, 1000 indicates no real hire date specified yet.
5 */
6 public class Employee
7 {
8 private String name;
9 private Date hireDate;
10 public Employee()
11 {
12 name = "No name";
13 hireDate = new Date("January", 1, 1000); //Just a placeholder.
14 }
15 /**
16 Precondition: Neither theName nor theDate is null.
17 */
18 public Employee(String theName, Date theDate)
19 {
20 if (theName == null || theDate == null)
21 {
22 System.out.println("Fatal Error creating employee.");
23 System.exit(0);
24 }
25 name = theName;
26 hireDate = new Date(theDate);
27 }
28 public Employee(Employee originalObject)
29 {
30 name = originalObject.name;
31 hireDate = new Date(originalObject.hireDate);
32 }
33 public String getName()
34 {
35 return name;
36 }
37 public Date getHireDate()
38 {
39 return new Date(hireDate);
40 }
41 /**
42 Precondition newName is not null.
43 */
44 public void setName(String newName)
45 {
46 if (newName == null)
47 {
48 System.out.println("Fatal Error setting employee name.");
49 System.exit(0);
50 }
51 else
52 name = newName;
53 }
54 /**
55 Precondition newDate is not null.
56 */
57 public void setHireDate(Date newDate)
58 {
59 if (newDate == null)
60 {
61 System.out.println("Fatal Error setting employee hire " + "date.");
62 System.exit(0);
63 }
64 else
65 hireDate = new Date(newDate);
66 }
67 public String toString()
68 {
69 return (name + " " + hireDate.toString());
70 }
71 public boolean equals(Employee otherEmployee)
72 {
73 return (name.equals(otherEmployee.name)
74 && hireDate.equals(otherEmployee.hireDate));
75 }
76 }
子类:HourlyEmployee
NB:7行:继承的heading;
13行的super();调用basic class的构造函数,如果不写这句默认也会去basic class中进行调用
24行super(theName, theDate); 也是调用basic class的函数
1 /**
2 Class Invariant: All objects have a name string, hire date, nonnegative
3 wage rate, and nonnegative number of hours worked. A name string of
4 "No name" indicates no real name specified yet. A hire date of
5 January 1, 1000 indicates no real hire date specified yet.
6 */
7 public class HourlyEmployee extends Employee
8 {
9 private double wageRate;
10 private double hours; //for the month
//构造函数
11 public HourlyEmployee()
12 {
13 super();
14 wageRate = 0;
15 hours = 0;
16 }
17 /**
18 Precondition: Neither theName nor theDate is null;
19 theWageRate and theHours are nonnegative.
20 */
21 public HourlyEmployee(String theName, Date theDate,
22 double theWageRate, double theHours)
23 {
24 super(theName, theDate);
25 if ((theWageRate >= 0) && (theHours >= 0))
26 {
27 wageRate = theWageRate;
28 hours = theHours;
29 }
30 else
31 {
32 System.out.println("Fatal Error: creating an illegal hourly employee.");
33
34 System.exit(0);
35 }
36 }
37 public HourlyEmployee(HourlyEmployee originalObject)
38 {
39 super(originalObject);
40 wageRate = originalObject.wageRate;
41 hours = originalObject.hours;
42 }
43 public double getRate()
44 {
45 return wageRate;
46 }
47 public double getHours()
48 {
49 return hours;
50 }
51 /**
52 Returns the pay for the month.
53 */
54 public double getPay()
55 {
56 return wageRate*hours;
57 }
58 /**
59 Precondition: hoursWorked is nonnegative.
60 */
61 public void setHours(double hoursWorked)
62 {
63 if (hoursWorked >= 0)
64 hours = hoursWorked;
65 else
66 {
67 System.out.println("Fatal Error: Negative hours worked.");
68 System.exit(0);
69 }
70 }
71 /**
72 Precondition: newWageRate is nonnegative.
73 */
74 public void setRate(double newWageRate)
75 {
76 if (newWageRate >= 0)
77 wageRate = newWageRate;
78 else
79 {
80 System.out.println("Fatal Error: Negative wage rate.");
81 System.exit(0);
82 }
83 }
84 public String toString()
85 {
86 return (getName() + " " + getHireDate().toString()+ "\n$" + wageRate + " per hour for " + hours + " hours");
87
88 }
89 public boolean equals(HourlyEmployee other)
90 {
91 return (getName().equals(other.getName())
92 && getHireDate().equals(other.getHireDate())
93 && wageRate == other.wageRate
94 && hours == other.hours);
95 }
96 }
--------------------------------------------------------------------------------------------------------------------------
(4)overriding a method definition
a) 介绍
重写一个方法就是:当子类继承了父类的方法后, 如果和父类的该方法需求不同,可以重新定义这个方法,也就是改变方法体的内容。比如上面提到的子类中重写了方法toString()
A derived class inherits methods that belong to the base class. However, if a derived class requires a different definition for an inherited method, the method may be redefined in the derived class. This is called overriding the method definition.
--------------------------------------------------------------------------------------------------------------------------
b)返回值类型
重写时不可以改变函数返回值的类型,比如父类的函数是void的不可以添加返回值,比如父类的函数有返回值,子类的函数不可以是void等。但是如何返回值是一个class类型,比如是Employee,那么子类的函数返回值可以是其类的子类HourlyEmployee。
This sort of changed return type is known as a covariant return type and is new in Java version 5.0;
比如:
--------------------------------------------------------------------------------------------------------------------------
c)函数的访问权限:public、private
You can change the access permission of an overridden method from private in the base class to public in the derived class
Note that you cannot change permissions to make them more restricted in the derived class.
You can change private to public , but you cannot change public to private
--------------------------------------------------------------------------------------------------------------------------
注意overloading 和overriding的区别
重写:是覆盖掉了父类中相同的方法,也就是目前只有一个方法可以被使用
重载:函数执行的内容是相同的,但是每个方法的参数不同,也就是说有很多的函数,并且做的事情都是相同的。
--------------------------------------------------------------------------------------------------------------------------
(5)The final Modifier
If you add the modifier final to the definition of a method, it indicates that the method may not be redefined in a derived class.
If you add the modifier final to the definition of a class, it indicates that the class may not be used as a base class to derive other classes.
--------------------------------------------------------------------------------------------------------------------------
(6)the super constructor
我们可以调用父类的构造函数,语法就是super(参数);
NB:1)如果想要使用super去调用父类的构造函数,比如把该语句放在子类构造函数的第一行。放到其他位置不可
2)不能将实例变量用作super的参数
3)These inherited instance variables should be initialized, and the base class constructor is the most convenient place to initialize these inherited instance variables.
4)如果不包括对基类构造函数的调用(使用super),则会自动调用基类的无参数构造函数。
比如:
--------------------------------------------------------------------------------------------------------------------------
(7)the this constructor
这个用法类似于super的用法,但是有了它,调用的是同一个类的构造函数,而不是基类的构造函数。
比如:
public HourlyEmployee()
{
this("No name", new Date("January", 1, 1000), 0, 0);
}
就相当于是调用:
public HourlyEmployee(String theName, Date theDate,double theWageRate, double theHours)
NB:1)You cannot use an instance variable as an argument to this .
2) any call to the constructor this must always be the first action taken in a constructor definition.
3)a constructor definition cannot contain both an invocation of super and an invocation of this
4)如果您希望同时包含对super的调用和对this的调用,请对this使用一个调用,并让用this调用的构造函数将super作为其第一个操作。
--------------------------------------------------------------------------------------------------------------------------
(8)当子类使用class作为super的参数时
比如:该语句使用 HourlyEmployee 作为参数,调用了父类的构造函数,但是父类并没有改参数的构造函数。但是仍然可以使用的原因是因为 HourlyEmployee 继承自父类,所以也就属于父类。(The fact that every object is not only of its own type but is also of the type of its ancestor classes simply reflects what happens in the everyday world)
--------------------------------------------------------------------------------------------------------------------------
7.2 encapsulation and inheritance(封装和继承)
(1)关于private的问题
如果想访问父类中private的instance variable, 那么只能通过父类中的方法,比如get()来进行访问。
比如:是子类中的toString() 函数
public String toString()
{
return (getName() + " " + getHireDate().toString() + "\n$" + wageRate + " per hour for " + hours + " hours");
}
NB:必须使用getName()来访问父类中的private变量,尽管子类有继承,但是因为私有的原因,不可以直接访问。因此下面的语句就是非法的。
public String toString() //Illegal version
{
return (name + " " + hireDate.toString() + "\n$" + wageRate + " per hour for " + hours + " hours");
}
但是private的方法就是可以看做是不可继承的,也就是不可以被子类所使用和访问。
--------------------------------------------------------------------------------------------------------------------------
(2)protected and package access
之前讨论的public 关键字,是可以在任何情况被使用的。
private只有本类可以使用,继承该类的子类只能通过使用父类中的public的方法来访问,正如上面所提到的
protect关键字是可以被自身的类和其子类直接访问,不用通过其他的方法就可以直接使用protected定义的instance variable。但是没有继承关系的类,如果是在同package中,也是可以直接访问的,但是不在同包也没有继承关系的,不可以直接访问。
package 的关键字。也就是在没有public、private和protected的修饰下,默认情况就是package access。它的访问情况是一种,同包下才可以访问,和继承等均无关。
几种情况的对比:
------------------------------------------------------------------------------------------------------------------------
pitfall: a restriction on protected access
package one;
public class B
{
protected int n;
...
}
package two;
import one.B;
public class D extends B
{
...
}
Then the following is a legitimate method that can appear in the definition of class D :
public void demo()
{
n = 42; //n is inherited from B.
}
The following is also a legitimate method definition for the derived class D :
public void demo2()
{
D object = new D();
object.n = 42; //n is inherited from B.
}
However, the following is not allowed as a method of D :
public void demo3()
{
B object = new B();
object.n = 42; //Error
}
在上面的例子中,n是基类b的实例变量和派生类d的实例变量。当n用作d的实例变量时,d可以访问n,但当n用作b的实例变量时,d不能访问n。
--------------------------------------------------------------------------------------------------------------------------
7.3 Programming with inheritance
(1) Invoking the Old Version of an Overridden Method?
Within the definition of a method of a derived class, you can invoke the base class version of an overridden method of the base class by prefacing the method name with super and a dot. Outside of the derived class definition, there is no way to invoke the base class version of an overridden method using an object of the derived class
例子:
//in the derived class HourlyEmployee
public String toString()
{
return (getName() + " " + getHireDate().toString() + "\n$" + wageRate + " per hour for " + hours + " hours");
}
//in the base class Employee
public String toString()
{
return (name + " " + hireDate.toString());
}
//in the derived class HourlyEmployee
public String toString()
{
return (super.toString() + "\n$" + wageRate + " per hour for " + hours + " hours");
}
但是多次使用super关键字是不合法的,比如:
super.super.toString() //ILLEGAL!