Java编程思想 - 第七章 - 复用类
复用代码是Java众多引人注目的功能之一。但要想成为极具革命性的语言,仅仅能够复制代码并对之加以改变是不够的,它还必须能够做更多的事情。
方法一,组合:在新的类中产生现有类的对象;
方法二,继承:采用现有类的形式并在其中添加新代码。
继承
继承并不只是复制基类的接口。当创建了一个导出类的对象时,该对象包含了一个基类的子对象。这个子对象与你用基类直接创建的对象是一样的。二者区别在于,后者来自于外部,而基类的子对象被包装在导出类对象内部。
对基类子对象的正确初始化是至关重要的,而是也仅有一种方法来保证这一点:在构造器中调用基类构造器来执行初始化,而基类构造器具有执行基类初始化所需要的所有知识和能力。Java会自动在导出烦的构造器中插入对基类构造器的调用。
class GrandParent {
GrandParent() {
System.out.println("Constructor of GrandParent");
}
}
class Parent extends GrandParent {
Parent() {
System.out.println("Constructor of Parent");
}
}
public class Son extends Parent {
public Son() {
System.out.println("Constructor of Son");
}
public static void main(String[] args) {
Son son = new Son();
}
}/* 输出结果:
Constructor of GrandParent
Constructor of Parent
Constructor of Son
*/
代理
第三种关系称为代理,Java并没有提供对它的直接支持。这是继承与组合之间的中庸之道,因为我们将一个成员对象置于所要构造的类中(就像组合),但与此同时我们在新类中暴露了该成员对象的所有方法(就像继承)。
在组合与继承之间选择
组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形。即,在新类中嵌入某个对象让其实现所需要的功能,但新类的用户看到的只是为新类所定义的接口,而非所嵌入对象的接口。
在继承的时候,使用某个现有类,并开发一个它的特殊版本。
“is-a”关系是用继承来表达的,而”has-a”的关系则是用组合来表达的。
protected关键字
protected关键字指明“就类用户而言,这是private的,但对于任何继承于此类的导出类或其他任何位于同一个包内的类来说,它却是可以访问的。(protected也提供了包访问权限)
向上转型
到底是该用组合还是继承,一个最清晰的判断方法就是问一问自己是否需要从新类向基类进行向上转型。如果必须向上转型,则继承是必要的;但如果不需要,则应当好好考虑自己是否需要继承。
final关键字
可能使用到final的有一种情况:数据、方法和类。
final数据
对于基本数据类型,final使数值恒定不变;对于对象引用,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象。然而,对象其自身却是可以被修改的,Java并未提供使任何对象恒定不变的途径。这一限制同样适用于数组,它也是对象。
空白final
必须在域的定义处或者每个构造器中用表达式对final进行赋值,这正是final域在使用前问题被初始化的原因所在。
final参数
在参数列表中以声明的方式将参数指明为final。这意味着你无法在方法中更改参数引用所指向的对象。
final方法
原因一,把方法锁定,以防任何继承类修改它的含义。
原因二,效率。(现在已大可不必)
final类
当某个类的整体定义为final时(通过将关键字final置于它的定义之前),就表明了你不打算继承该类,而且也不允许别人这样做。
类的加载
一般来说,可以说:“类的代码在初次使用时才加载。”这通常是指加载属于于创建类的第一个对象之时,但是当访问static域或static方法时,也会发生加载(构造器也是static方法,尽管static关键字没有显式地写出来。因此更准确地讲,类是在其任何static成员被访问时加载的)