一、继承的基础
在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同样可以访问被子类隐藏的超类的成员方法。