Ⅶ 复用类
复用代码是Java众多引人注目的功能之一,Java的代码复用都是围绕类来展开的。所以很多时候,不需要重复去造轮子,而是可以直接调试使用他人写好的类库框架。当然,在现阶段,自己动手才是最好的学习方式。
Java的代码复用方式主要有两种:
- 组合:在新的类中产生现有类的对象。
- 继承:通过现有的类型来创建新类。
7.1 组合语法
- 在前文关于初始化的部分中提到,Java类钟域为基本数据类型时能自动初始化某默认值(具体可以去查表),对象引用默认会被初始化为null。 其实编译器并不是简单地为每一个引用都创建默认对象,因为这样的好处是可以减轻某些不必要的负担与开销。如果明确想要初始化这些引用,可以在以下几个位置进行:
- 在定义对象的地方,这将在调用构造器之前被初始化。
class Wheel{ private String type; Wheel{}{ }//Class Car{ private Wheel w=new Wheel();}}复制代码
- 在类的构造器中。
class Wheel{ private String type; Wheel{}{ }//Class Car{ private Wheel w; Car (){ this.w=new Wheel(); }`}}复制代码
- 在需要使用到这些对象时,这种被称为惰性初始化。
7.2 继承语法
- 在子类中完全可以使用基类中的方法并对它进行修改。假如基类中有个方法叫
take()
,你想要在子类的take()
方法中不对基类方法进行修改,那么不能直接在子类的take()
中调用take()
,因为这会产生递归。而是需要在子类的take()
中super.take()
。
7.3 代理
-
代理是介于继承和组合中间的一种方式,Java没有对其直接支持。代理是什么意思? 比如我们把一个成员对象置于所要构建的新类中(组合),但是需要在新类中暴露这个对象的所有方法(继承)(不适合使用继承的另一个原因是也往往违背了is-a关系)。
-
实际用法是需要在新类中再次对这个对象的方法进行封装描述,这有点麻烦,但是好处是使用代理时可以获得多个对象得不同能力,而且也可以取其子集。
7.4 结合使用组合和继承
-
有时记得进行必要的清理,在清理时注意对基类清理方法和对成员对象清理方法的调用顺序,其顺序应该和生成对象的顺序相反。
-
大多数情况下,清理不是问题,仅仅交给垃圾回收器来做就行了。但有必要时,需要我们手动处理。最好的办法是除内存以外,不要依赖垃圾回收器做其他清理工作。当需要进行必要的清理时,编写你自己的方法,但不要使用前文提到的
finalize()
。 -
相较于继承,组合方式往往更常用,尽管在学习OOP时,我们强调继承这一概念。那么到底什么情况下使用继承?一个比较好的方法是,考虑在工程中,是否有需要从新类向基类进行向上转型。如果必须向上转型,那么继承是必要的。
7.7 向上转型
- 向上转型是一个专用的类型向通用类型转换,所以总是很安全的。在向上转型的过程中,类接口中可能发生的情况是丢失方法。
7.8 final关键字
在不同的上下文环境中,final
有着细微的区别,它通常是来表示“不可改变的”,当然也存在着特殊的情况。
final
一般有三种使用场景:数据、方法、类。
7.8.1 数据
-
编译期常量,是使用
final
修饰的基本数据类型,在定义时必须进行赋值。这是一种使数据恒定不变的方式。 -
在使用
final
修饰一个引用时,final
使引用固定地指向一个对象,但是这个对象本身是可以修改的。 -
被
final
修饰的数据并不代表我们在编译期就可以知道它的值。比如:
static Random rand=new Random(10);final int a=rand.nextInt(10);复制代码
- 值得一提的是,还可以用
final
来修饰方法参数,当一个参数被final
修饰后,意味着在这个方法中,无法改变参数引用所指向的对象了。
7.8.2 方法
final
方法的用处有两个:
- 锁定方法,防止在继承类中被重写。(这是出于一些情况的设计,需要确保在继承中此被继承方法的功能不变)
- 过去使用
final
修饰方法可能是出于效率的考量,但是现在并不是很需要。(如果将一个方法指明为final
,就是同意编译器将针对该方法的所有调用都转为内嵌调用。在后续版本中这样效率反而降低,已经不需要了。)
- 所有的
private
方法其实都是隐式地被指定为final
。如果你试图去覆盖一个private
方法,似乎是奏效的,因为编译器没有报错,但实际是不对的,可以编写代码来测试。这里就不演示了。 覆盖只有在子类中某方法是基类的接口的一部分时才会出现。private
修饰的方法,不会是基类接口的一部分。
7.8.3 类
- 使用
final
修饰的类无法被继承。当然,其中的方法也无法被覆盖。
7.10 总结
-
继承和组合都能从现有类型生成新类型。组合一般是将现有类型作为新类型底层实现的一部分来加以复用,继承复用的是接口。
-
子类拥有父类接口,所以可以向上转型,这对多态来说至关重要。
小白的成长探索之路。