第7章 复用类

7.2 继承语法

如果基类没有默认构造函数,那么必须在Derive类的构造函数中显示调用Base类的带参构造函数。

 1 import static java.lang.System.out;
 2 class Base {
 3   Base(String name){
 4     out.println("Base constructor");
 5   }
 6 }
 7 
 8 public class Derive extends Base {
 9   Derive(){
10     super("test"); /* If comment out this line, result a compile error*/
11   }
12   public static void main(String args[]){
13   }
14 }

如果基类具有默认构造函数,那么编译器会帮你在Derive类的构造函数中黯然插入对于基类默认构造函数的掉用。


 1 import static java.lang.System.out;
 2 class Base {
 3   Base(){
 4     out.println("Base constructor");
 5   }
 6   Base(String name){
 7     out.println("Base constructor with one parameter");
 8   }
 9 }
10 
11 public class Derive extends Base {
12   Derive(){
13     //super(); /*Compilor inserts this line for you implicity*/
14   }
15   Derive(String name){
16     //super(); /*Compilor inserts this line for you implicity*/
17   }
18   public static void main(String args[]){
19     new Derive();
20     new Derive("name");
21   }
22 }/* Output:
23 Base constructor
24 Base constructor
25 */

7.4 结合使用组合和继承

7.4.2 名称屏蔽

C++中重载只可以发生在水平层面上(即同一个类中,同一个作用域中),英文记做overloading。而一旦这种overloading的表现出现在垂直层面上(即继承体系上,一般是Derive类中声明一个方法的名称与Base类中的某个方法相同),英文记做overriding,也就是说overloading在垂直层面上不存在。而Derive类可以通过override一个在Base类中被声明为virtual的方法(这个方法在Base类和Derive类中的方法签名必须完全相同,亦即function name+parameter list必须完全相同,但return type可以是Base类方法return type的子类。详细参见这里:http://stackoverflow.com/questions/4665117/c-virtual-function-return-type)来实现runtime polymorphism。当overloading出现在处置层面的时候,并且方法没有被标记为virtual,那么父类的方法就被子类覆盖了,记住:被覆盖的不是某一个具体的方法,而是具有这个方法签名的所有方法。

Java中所有的方法默认都是Runtime绑定的,Java中的Overloading可以发生在不同层面上(Derive类中定义的方法与Base类中的相同签名的方法构成overloading),Java中可以用@Override 让Compiler帮助你正确的Override一个方法(你可能错误的进行了overloading)

 1 import static java.lang.System.out;
 2 class Base {
 3   void f(){}
 4 }
 5 public class Test extends Base {
 6   @Override
 7   void f(int i){} /*Result a compile errror unless remove parameter declaration*/  
 8   public static void main(String args[]){
 9   }
10 }

7.8 final关键字

7.8.1 final数据

 1 public class Test{
 2     private final int a = 1;
 3       private final int b; //Blank final
 4     {
 5         //a = 2; //final data can not reassign
 6           b = 4;
 7     }
 8       
 9       public Test(){
10         //a = 3; //final data can not reassign
11     }
12     public static void main(String args[]){
13           new Test();
14     }
15 }

或者

 1 public class Test{
 2     private final int a = 1;
 3       private final int b; //Blank final
 4       
 5       public Test(){
 6         //a = 3; //final data can not reassign
 7           b = 4;
 8     }
 9     public static void main(String args[]){
10           new Test();
11     }
12 }

final数据也可以是local的哟~

1 public class Test{
2     public static void main(String args[]){
3           final int i;
4           i = 3;
5           //i = 5; /* This result a compile error */
6     }
7 }

final基本类型的数据值不可变,final对象类型的数据引用不可变对象本身可变,Java在语法上不提供对象本身不可变的方法。

final参数与C++中的const reference parameter有着相同的效果:你不可以更改引用的对象,但被引用对象的内容的修改不受此关键字的限制。

 7.8.2 final方法

final方法阻止Derive类修改它的含义,也就是组织了多态。

Java5之前final方法还对编译器施加了类似于C++中inline的作用。但现在已经不再提倡。

private的方法意义上等同与final,但对于Derive类override的限制上有着不同的行为,详细看如下代码。

 1 class Base {
 2   private void f1() {}
 3   private final void f2() {}
 4   public final void g() {}
 5 }
 6 
 7 public class Derive extends Base {
 8   void f1() {}
 9   void f2() {}
10   /* This result a compile error : g() in Derive cannot override g() in Base, for overridden method is final*/
11   void g() {}
12   public static void main(String args[]){}
13 }

7.8.3 final类

语法上阻止了被声明为final的类被他人extends。

让我们来回忆一下如何在C++中实现这种效果,注意C++的语法:class中默认访问权限为private。

 1 class UnDerived {
 2     UnDerived(){}
 3 };
 4 
 5 class Derive : UnDerived {
 6 };
 7 
 8 int main()
 9 {
10    Derive d;
11    return 0;
12 }/* Compile output:
13 main.cpp: In constructor 'Derive::Derive()':
14 main.cpp:2:5: error: 'UnDerived::UnDerived()' is private
15 main.cpp:5:7: error: within this context
16 main.cpp: In function 'int main()':
17 main.cpp:10:11: note: synthesized method 'Derive::Derive()' first required here
18 */

7.9 初始化及类的加载

类的加载顺序为,先遇到先加载,某个类如果有基类,那么它的基类也会被加载。

 1 import static java.lang.System.out;
 2 class Indicator {
 3   Indicator(String name){
 4     out.println(name);
 5   }
 6 }
 7 
 8 class Base {
 9   static Indicator i1 = new Indicator("i1");
10   static Indicator i2;
11   static {
12     i2 = new Indicator("i2");
13   }
14   Base(){} 
15 }
16 
17 public class Derive extends Base {
18   static Indicator i6 = new Indicator("i6");
19   static Indicator i7;
20   static {
21     i7 = new Indicator("i7");
22   }
23   Derive(){}
24   public static void main(String args[]){
25   }
26 }/*
27 i1
28 i2
29 i6
30 i7
31 */

 

构造函数以及Static域的初始化顺序为先基类后子类。

确切的描述为:

  1. 加载子类,加载基类,加载根基类
  2. 根基类的static初始化,基类,最后是子类
  3. 根基类的构造函数被调用,基类,最后是子类

 

 1 import static java.lang.System.out;
 2 class Indicator {
 3   Indicator(String name){
 4     out.println(name);
 5   }
 6 }
 7 
 8 class Base {
 9   static Indicator i1 = new Indicator("i1");
10   static Indicator i2;
11   static {
12     i2 = new Indicator("i2");
13   }
14   private Indicator i3 = new Indicator("i3");
15   private Indicator i4;
16   private Indicator i5;
17   {
18     i4 = new Indicator("i4");
19   }
20   
21   Base(){
22     i5 = new Indicator("i5");
23   } 
24 }
25 
26 public class Derive extends Base {
27   static Indicator i6 = new Indicator("i6");
28   static Indicator i7;
29   static {
30     i7 = new Indicator("i7");
31   }
32   private Indicator i8 = new Indicator("i8");
33   private Indicator i9;
34   private Indicator ia;
35   {
36     i9 = new Indicator("i9");
37   }
38   Derive(){
39     ia = new Indicator("ia");
40   }
41   public static void main(String args[]){
42     new Derive();
43   }
44 }/*
45 i1
46 i2
47 i6
48 i7
49 i3
50 i4
51 i5
52 i8
53 i9
54 ia
55 */

 

 

 

 

posted on 2013-05-02 13:44  peter9606  阅读(123)  评论(0编辑  收藏  举报

导航