一、继承的基础
在Java术语中,被继承的类叫超类(superclass)或者父类,继承超类的类叫子类(subclass).
举例说明:
class Box
{
public double width;
public double height;
public double depth; //重载构造方法
public Box(Box ob)
{
width = ob.width;
height = ob.height;
depth = ob.depth;
} public Box(double w, double h, double d)
{
width = w;
height = h;
depth = d;
} public Box()
{
width = -1;
height = -1;
depth = -1;
} public Box(double len)
{
width = height = depth = len;
} //计算体积
public double volume()
{
return width * height * depth;
}
} //下面的类继承自类Box
class BoxWeight extends Box
{
double weight; //BoxWeight的构造方法
BoxWeight (double w, double h, double d, double m)
{
width = w;
height = h;
depth = d;
weight = m;
}
} public class DemoBoxWeight
{
public static void main(String args[])
{
BoxWeight mybox1 = new BoxWeight(10, 20, 15, 34.3);
BoxWeight mybox2 = new BoxWeight(2, 3, 4, 0.076);
double vol; vol = mybox1.volume();
System.out.println("Volume of mybox1 is " + vol);
System.out.println("Weight of mybox1 is " + mybox1.weight);
System.out.println();
vol = mybox2.volume();
System.out.println("Volume of mybox2 is " + vol);
System.out.println("Weight of mybox2 is " + mybox2.weight);
}
}
如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,下图对各种控制模式的允许访问范围作一个总结:
三、超类变量可以引用子类对象
class Box
{
public double width;
public double height;
public double depth; //重载构造方法
public Box(Box ob)
{
width = ob.width;
height = ob.height;
depth = ob.depth;
} public Box(double w, double h, double d)
{
width = w;
height = h;
depth = d;
} public Box()
{
width = -1;
height = -1;
depth = -1;
} public Box(double len)
{
width = height = depth = len;
} //计算体积
public double volume()
{
return width * height * depth;
}
} //下面的类继承自类Box
class BoxWeight extends Box
{
double weight; //BoxWeight的构造方法
BoxWeight (double w, double h, double d, double m)
{
width = w;
height = h;
depth = d;
weight = m;
}
}
class RefDemo
{
public static void main(String args[])
{
BoxWeight weightbox = new BoxWeight(3, 5, 7, 8.37);
Box plainbox = new Box();
double vol; vol = weightbox.volume();
System.out.println("Volume of weightbox is " + vol);
System.out.println("Weight of weightbox is " +
weightbox.weight);
System.out.println();
// assign BoxWeight reference to Box reference
plainbox = weightbox; vol = plainbox.volume(); // OK, volume() defined in Box
System.out.println("Volume of plainbox is " + vol); /* The following statement is invalid because plainbox
does not define a weight member. */
// System.out.println("Weight of plainbox is " + plainbox.weight);
}
}
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里面参数的形式决定调用哪一个构造方法,看下面程序:
class Box
{
//成员全部“私有化”
private double width;
private double height;
private double depth; //重载构造方法
public Box(Box ob)
{
width = ob.width;
height = ob.height;
depth = ob.depth;
} public Box(double w, double h, double d)
{
width = w;
height = h;
depth = d;
} public Box()
{
width = -1;
height = -1;
depth = -1;
} public Box(double len)
{
width = height = depth = len;
} //计算体积
public double volume()
{
return width * height * depth;
}
} //下面的类继承自类Box
class BoxWeight extends Box
{
double weight; //用super调用BoxWeight的构造方法
BoxWeight(BoxWeight ob)
{
super(ob);
weight = ob.weight;
} BoxWeight (double w, double h, double d, double m)
{
super(w, h, d);
weight = m;
}
// default constructor
BoxWeight() {
super();
weight = -1;
} BoxWeight(double len, double m) {
super(len);
weight = m;
}
}
public class myJavaTest
{
public static void main(String args[]) {
BoxWeight mybox1 = new BoxWeight(10, 20, 15, 34.3);
BoxWeight mybox2 = new BoxWeight(2, 3, 4, 0.076);
BoxWeight mybox3 = new BoxWeight(); // default
BoxWeight mycube = new BoxWeight(3, 2);
BoxWeight myclone = new BoxWeight(mybox1);
double vol; vol = mybox1.volume();
System.out.println("Volume of mybox1 is " + vol);
System.out.println("Weight of mybox1 is " + mybox1.weight);
System.out.println(); vol = mybox2.volume();
System.out.println("Volume of mybox2 is " + vol);
System.out.println("Weight of mybox2 is " + mybox2.weight);
System.out.println(); vol = mybox3.volume();
System.out.println("Volume of mybox3 is " + vol);
System.out.println("Weight of mybox3 is " + mybox3.weight);
System.out.println(); vol = myclone.volume();
System.out.println("Volume of myclone is " + vol);
System.out.println("Weight of myclone is " + myclone.weight);
System.out.println();
vol = mycube.volume();
System.out.println("Volume of mycube is " + vol);
System.out.println("Weight of mycube is " + mycube.weight);
System.out.println();
}
}
运行结果:
这里特别注意这个构造方法:
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同样可以访问被子类隐藏的超类的成员方法。