一、继承的基础
在Java术语中,被继承的类叫超类(superclass)或者父类,继承超类的类叫子类(subclass).
举例说明:
1 class Box
2 {
3 public double width;
4 public double height;
5 public double depth;
6
7 //重载构造方法
8 public Box(Box ob)
9 {
10 width = ob.width;
11 height = ob.height;
12 depth = ob.depth;
13 }
14
15 public Box(double w, double h, double d)
16 {
17 width = w;
18 height = h;
19 depth = d;
20 }
21
22 public Box()
23 {
24 width = -1;
25 height = -1;
26 depth = -1;
27 }
28
29 public Box(double len)
30 {
31 width = height = depth = len;
32 }
33
34 //计算体积
35 public double volume()
36 {
37 return width * height * depth;
38 }
39 }
40
41 //下面的类继承自类Box
42 class BoxWeight extends Box
43 {
44 double weight;
45
46 //BoxWeight的构造方法
47 BoxWeight (double w, double h, double d, double m)
48 {
49 width = w;
50 height = h;
51 depth = d;
52 weight = m;
53 }
54 }
55
56 public class DemoBoxWeight
57 {
58 public static void main(String args[])
59 {
60 BoxWeight mybox1 = new BoxWeight(10, 20, 15, 34.3);
61 BoxWeight mybox2 = new BoxWeight(2, 3, 4, 0.076);
62 double vol;
63
64 vol = mybox1.volume();
65 System.out.println("Volume of mybox1 is " + vol);
66 System.out.println("Weight of mybox1 is " + mybox1.weight);
67 System.out.println();
68 vol = mybox2.volume();
69 System.out.println("Volume of mybox2 is " + vol);
70 System.out.println("Weight of mybox2 is " + mybox2.weight);
71 }
72 }
如42行所示,声明一个继承超类的类,需要用到关键字extends,形式如下:
class subclass-name extends superclass-name {
// body of class
}
子类BoxWeight 包括超类Box所有成员,这就是为什么在49-51行中子类可以直接给超类的成员赋值,并且子类对象mybox1可以调用超类方法volume()的原因。而且一个子类可以是另一个类的超类。
但是一个子类只允许有一个超类(这与C++不同,C++中派生类可以继承多个基础类),任何类不能成为自己的超类。
运行结果:
继承的一个主要优势在于一旦你已经创建了一个超类,而该超类定义了适用于一组对象的属性,它可用来创建任何数量的说明更多细节的子类。每一个子类能够正好制作它自己的分类。上面的BoxWeight类继承了Box并增加了一个重量属性。 每一个子类只增添它自己独特的属性。
二、成员的访问权限和继承
尽管子类包括超类的所有成员,但是它不能访问超类中被声明成private的成员,一个被类定义成private的类成员为此类私有,它不能被该类外的所有代码访问。
类成员的访问控制通常有四种public,protected,default,private,下图对各种控制模式的允许访问范围作一个总结:
三、超类变量可以引用子类对象
1 class Box
2 {
3 public double width;
4 public double height;
5 public double depth;
6
7 //重载构造方法
8 public Box(Box ob)
9 {
10 width = ob.width;
11 height = ob.height;
12 depth = ob.depth;
13 }
14
15 public Box(double w, double h, double d)
16 {
17 width = w;
18 height = h;
19 depth = d;
20 }
21
22 public Box()
23 {
24 width = -1;
25 height = -1;
26 depth = -1;
27 }
28
29 public Box(double len)
30 {
31 width = height = depth = len;
32 }
33
34 //计算体积
35 public double volume()
36 {
37 return width * height * depth;
38 }
39 }
40
41 //下面的类继承自类Box
42 class BoxWeight extends Box
43 {
44 double weight;
45
46 //BoxWeight的构造方法
47 BoxWeight (double w, double h, double d, double m)
48 {
49 width = w;
50 height = h;
51 depth = d;
52 weight = m;
53 }
54 }
55 class RefDemo
56 {
57 public static void main(String args[])
58 {
59 BoxWeight weightbox = new BoxWeight(3, 5, 7, 8.37);
60 Box plainbox = new Box();
61 double vol;
62
63 vol = weightbox.volume();
64 System.out.println("Volume of weightbox is " + vol);
65 System.out.println("Weight of weightbox is " +
66 weightbox.weight);
67 System.out.println();
68 // assign BoxWeight reference to Box reference
69 plainbox = weightbox;
70
71 vol = plainbox.volume(); // OK, volume() defined in Box
72 System.out.println("Volume of plainbox is " + vol);
73
74 /* The following statement is invalid because plainbox
75 does not define a weight member. */
76 // System.out.println("Weight of plainbox is " + plainbox.weight);
77 }
78 }
weightbox是BoxWeight对象的一个引用,plainbox是Box对象的一个引用(关于JAVA中引用的概念和C++有些不同,可以参考http://blog.sina.com.cn/s/blog_7fb1495b01012sfn.html,写的很详细)。既然 BoxWeight是Box的一个子类,允许用一个weightbox对象的引用给plainbox赋值,但是plainbox是不可以访问weight的,因为超类不知道子类增加的属性weight,所以最后一行被注释掉,Box的引用访问weight域是不可能的,因为它没有定义这个域。
四、关于super
super有两种通用形式。第一种调用超类的构造方法。第二种用来访问被子类的成员隐藏的超类成员。
- 使用super调用超类构造函数
考虑下面BoxWeight()的改进版本:
class BoxWeight extends Box
{
double weight;
//BoxWeight的构造方法
BoxWeight (double w, double h, double d, double m)
{
super(w, h, d);// 调用超类构造方法
weight = m;
}
}
这样Box完全可以把成员width,height,depth声明为private,子类在初始化这些成员时并没有自己动手,而是调用超类的构造方法去初始化这些值(超类自己的构造方法显然可以访问自己private成员),这样有利于超类的封装。而且超类将根据super里面参数的形式决定调用哪一个构造方法,看下面程序:
1 class Box
2 {
3 //成员全部“私有化”
4 private double width;
5 private double height;
6 private double depth;
7
8 //重载构造方法
9 public Box(Box ob)
10 {
11 width = ob.width;
12 height = ob.height;
13 depth = ob.depth;
14 }
15
16 public Box(double w, double h, double d)
17 {
18 width = w;
19 height = h;
20 depth = d;
21 }
22
23 public Box()
24 {
25 width = -1;
26 height = -1;
27 depth = -1;
28 }
29
30 public Box(double len)
31 {
32 width = height = depth = len;
33 }
34
35 //计算体积
36 public double volume()
37 {
38 return width * height * depth;
39 }
40 }
41
42 //下面的类继承自类Box
43 class BoxWeight extends Box
44 {
45 double weight;
46
47 //用super调用BoxWeight的构造方法
48 BoxWeight(BoxWeight ob)
49 {
50 super(ob);
51 weight = ob.weight;
52 }
53
54 BoxWeight (double w, double h, double d, double m)
55 {
56 super(w, h, d);
57 weight = m;
58 }
59 // default constructor
60 BoxWeight() {
61 super();
62 weight = -1;
63 }
64
65 BoxWeight(double len, double m) {
66 super(len);
67 weight = m;
68 }
69 }
70 public class myJavaTest
71 {
72 public static void main(String args[]) {
73 BoxWeight mybox1 = new BoxWeight(10, 20, 15, 34.3);
74 BoxWeight mybox2 = new BoxWeight(2, 3, 4, 0.076);
75 BoxWeight mybox3 = new BoxWeight(); // default
76 BoxWeight mycube = new BoxWeight(3, 2);
77 BoxWeight myclone = new BoxWeight(mybox1);
78 double vol;
79
80 vol = mybox1.volume();
81 System.out.println("Volume of mybox1 is " + vol);
82 System.out.println("Weight of mybox1 is " + mybox1.weight);
83 System.out.println();
84
85 vol = mybox2.volume();
86 System.out.println("Volume of mybox2 is " + vol);
87 System.out.println("Weight of mybox2 is " + mybox2.weight);
88 System.out.println();
89
90 vol = mybox3.volume();
91 System.out.println("Volume of mybox3 is " + vol);
92 System.out.println("Weight of mybox3 is " + mybox3.weight);
93 System.out.println();
94
95 vol = myclone.volume();
96 System.out.println("Volume of myclone is " + vol);
97 System.out.println("Weight of myclone is " + myclone.weight);
98 System.out.println();
99 vol = mycube.volume();
100 System.out.println("Volume of mycube is " + vol);
101 System.out.println("Weight of mycube is " + mycube.weight);
102 System.out.println();
103 }
104 }
运行结果:
这里特别注意这个构造方法:
BoxWeight(BoxWeight ob)
{
super(ob); //子类对象赋给超类对象
weight = ob.weight;
}
可以看出一个超类引用了子类对象,但是超类只知道它自己的成员,而weight它是不知道的,需要单独初始化。
特别记住,super()必须是子类构造方法中第一个执行的语句。
- super的第二种用法
通用形式:super.超类的成员域, 其中“超类的成员域”可以是成员变量和成员方法。多数是用于超类成员名被子类中同样的成员名隐藏的情况,看一个简单的例子:
1 class A
2 {
3 int xiaoming;
4 }
5
6 class B extends A {
7 int xiaoming; // 这子类中的同名变量xiaoming会隐藏超类中的xiaoming
8
9 B(int a, int b) {
10 super.xiaoming = a; // xiaoming in A
11 xiaoming = b; // xiaoming in B
12 }
13
14 void show()
15 {
16 System.out.println("xiaomingin superclass: " + super.xiaoming);
17 System.out.println("xiaoming in subclass: " + xiaoming);
18 }
19 }
20
21 class UseSuper
22 {
23 public static void main(String args[])
24 {
25 B subOb = new B(1, 2);
26
27 subOb.show();
28 }
29 }
输出如下:
xiaoming in superclass: 1
xiaoming in subclass: 2
这个例子只是展示了super可以访问被子类隐藏的超类的成员变量,但是不要忘记,super同样可以访问被子类隐藏的超类的成员方法。