java中,复用代码有两种途径:
- 在新的类中产生现有类的对象。由于新的类是由现有类的对象组成的,所以这种方法称为组合。
- 采用继承的方式来复用。
继承
继承采用关键字extends实现。
java用super关键字表述超类的意思。
初始化基类
当创建一个子类的对象时,该对象包含了一个基类的子对象。这个子对象与你用基类创建的对象是一样的。对基类子对象的正确初始化也至关重要,而且也只有一种方法来保证这一点:在构造器中调用基类的构造器执行初始化。看下面这个例子:
public class Cartoon extends Drawing{ public Cartoon() { System.out.println("Cartoon constructor"); } public static void main(String [] args){ Cartoon cartoon = new Cartoon(); } } class Art{ Art() { System.out.println("Art constructor"); } } class Drawing extends Art { public Drawing() { System.out.println("Drawing constructor"); } }
Art constructor
Drawing constructor
Cartoon constructor
可以发现,构建过程是从基类“向外”扩散的。如果构造器要带有参数,则子类构造其需要显示的用super调用基类的构造器。
在组合与继承之间选择
组合和集成都允许在新的类中放置子对象,组合是显示的这样做,而继承则是隐示的这样做。这二者该如何选择呢?这里有个规则:“is-a”(是一个)的关系用继承来表达的。而“has-a”(有一个)的关系则是用组合来表达的。
向上转型
每个子类都可以看作为它基类的类型。这个过程称为向上转型。
final关键字(类似c++ 中的 const)
final关键字通常指的是“这是无法改变的”。final常用于基本类型,表示final使数值恒定不变。而对于对象引用设为final,则表示引用恒定不变。一旦引用被初始化指向一个对象,将无法在把它指向其他对象。然而,对象自身的值确实可以被改变的。
空白final,指被声明为final但又未给定初值的域。这种情况将要求你一定在类构造器为其初始化。如:
public class Cartoon extends Drawing{ private final int i; public Cartoon() { i = 0; System.out.println("Cartoon constructor"); } public static void main(String [] args){ Cartoon cartoon = new Cartoon(); } }
final参数,指在参数列表中将参数声明为final,则在方法中无法更改final所指参数。
final方法,用于将方法锁定,以防任何继承类修改它。
类中所有的private方法都隐示的指定为final的。由于无法取用private方法,所以u也就无法覆盖它。可以对private方法添加final修饰词,但并未产生额外的意义。但这个问题很容易造成误解。因为,如果你试图覆盖一个private方法(隐含是final的),似乎是奏效的,而且编译器也不会给出错误信息。如下所示:
public class Cartoon extends Drawing{ public Cartoon() { System.out.println("Cartoon constructor"); } private void play(){ System.out.println("Cartoon play"); } public static void main(String [] args){ Cartoon cartoon = new Cartoon(); } } class Drawing { public Drawing() { System.out.println("Drawing constructor"); } private void play(){ System.out.println("Drawing play"); } }
程序并没报错。这是因为“覆盖”只有在某方法是基类的接口的一部分时才出现。而上例中基类Drawing中的play()方法是private的,是被隐藏的,Cartoon类无法接触的。所以即使Cartoon类中创建了play()方法,它也不是对基类方法的覆盖,而是直接创建了一个新的方法。
final类表示禁止继承该类。