Java学习笔记之继承

一、继承的基础

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

 

 

 

posted @ 2014-08-19 20:29  90Zeng  阅读(960)  评论(0编辑  收藏  举报