Chapter 7 Reusing Classes
组合和继承是复用类的两个基本方法。
7.1 组合语法
- 组合是复用的基础方法之一,将对象引用置于新类中即可。
- 作为成员的对象需要在使用前确保初始化。
7.2 继承语法
- 继承基类的子类会得到积累的所有域和方法。
基类的初始化
- 当创建一个子类的对象实例时,该对象会包含基类的成员对象。
- 对于基类的静态成员,子类会继承其引用。
- 为此需要确保基类的初始化,执行子类的构造函数前,会自动调用基类的默认构造函数。
- 可以使用super来显示调用子类的其他构造函数,并将其置于构造函数的第一句,这样就不会自动调用父类的默认构造函数。
7.3 代理
代理就是将一个成员对象置于所要构造的类中(组成),并在新类中暴露了该成员对象所有的方法(继承),以对该成员对象的方法添加其他执行过程。
- IDEA可以生成代理类
7.4 结合组合和继承
- 在实际开发中结合组合和继承是非常常见的。
- 如果需要清理组合的成员对象,需要显示地进行处理,如使用finally。
- 使用JAVA5的@override来确保方法覆盖。
7.5 在组合与继承之间选择
- 组合计数通常用于在新类中使用现有类的功能。
- 继承需要满足'is-a'的关系,应该更关注于接口和其实现。统一不同的代码流程。
7.6 protected关键字
- protected访问权限提供了子类和包内的访问。
- 应该使用private来保留改变底层实现的权利,然后通过protected控制子类的访问权限。
7.7 向上转型
- 继承技术除了为新的类提供方法外,更重要的方面是表现新类和基类之间的关系("is-a")。
- 将子类的引用转换为父类引用的动作,称为向上转型。
- 向上转型是一种安全的转换,可以用来统一不同的代码。
- 只有当需要向上转型时才需要使用继承(is-a关系)。
7.8 final关键字
Java的关键字final表示"不法改变的"。
final数据
- final static基本数据类型和String能够成为编译时常量,只有一份,减轻运行负担。
- final对象引用,引用无法改变,但对象自身可以改变。
- final方法参数能够表明方法不会改变基本数据类型的参数变量。
final方法
- final方法能够保证无法被覆盖修改。
- final方法在初期能够提升编译器方法调用的效率,Java5的JVM开始基本不需要了。
final类
- fiinal类无法被继承,其域和方法都被定义为final。
有关final的忠告
- 将方法指明为final,一般是类库开发者为了不让别人继承这些类的一种指导。
- 你无法猜测将来人们会怎么使用你的类。
7.9 初始化及类的加载
- 在Java中,加载的单元是一个类(.class文件)。
- 在初次使用类的时才会对类程序代码进行加载,包括创建对象和访问static域或方法。
- 加载时,所有static对象和static代码会按书写顺序依次初始化一次。
继承与初始化
再次回顾加载过程:
- 父类静态成员自动初始化
- 父类静态初始块、父类静态成员指定初始化
- 子类静态成员自动初始化
- 子类静态初始块、类静态成员指定初始化
- 父类初始块、父类成员变量指定初始化
- 父类构造函数(若没有在构造器里super指定,调用无参构造函数)
- 子类初始块、子类成员变量指定初始化
- 子类构造函数
- 当在一个类文件上运行Java时,首先试图访问该类的main()方法(static)。
- 于是加载器开始启动并通过package对应os目录找到编译代码(.class文件)。
- 开始加载时,编译器先通过extends得知基类的存在,于是优先加载基类。
- 基类的static初始化开始被执行,按书写顺序进行静态域的初始化。
- 然后开始进行子类的static初始化(因为子类的static域可能依赖于基类)。
- 至此,类已加载完毕没开始进行对象创建的过程。
- 首先对象的基本类型数据设为默认值(自动初始化),对象引用设为null(二进制0)。
- 之后开始执行基类的构造函数(自动调用默认构造函数,或者通过super指定),然后子类构造函数其他部分。
7.10 总结
- 继承和组合都是复用类(代码)的基本方式,优先考虑组合,只有当需要向上转型的时候才用继承。
- 程序开发是一个增量过程,开发项目时无法知道所有的答案,所以将项目视作一种有机的、进化这的生命体而去培养(并通过访问控制机、final对其进化进行一定的限制)。