《数据结构与算法分析Java语言描述》第一章1.4与1.5节读书笔记
1. 范型
范型机制:如果对象除去基本类型外,其余的实现方法相同,可以用范型实现来描述。
1.1 使用Object表示范型
Object类是所有类的超类,可以通过Object类实现范型类。
1 | public class MemoryCell { |
- 注意,如果需要一个特定的类型使用,则需要强制转为正确的类型。
- 不能使用基本类型(8大类型),只有引用类型(类、接口类型、数组类型、枚举类型)与Object相容。(这里测试实际是可以的(Java8):自动拆装箱)
1.2 包装类型
Java提供了8种基本类型,这8种类型不能与Objecct相容,所以Java提供了对应的包装类。
1.3 使用接口表示范型
只有在使用Object类中已有的方法能够表示所执行的操作时,才能使用Object作为范型类工作。(与代码对象类型无关)。
例如找出Object数组中的最大项,与类型无关,只能实现Comparable接口,重写compareTo方法。
1.5 利用Java范型特性
Java支持范型类与范型方法
1.5.1 简单范型类和接口
在类上使用<范型>,表示一个范型类。如下是前面的MemoryCell类范型版代码。也可以实现范型接口。
1 | public class GenericMemoryCell<T> { |
1.5.2 自动拆箱/装箱
自动装箱:如果一个基本类型,例如int被传递到一个需要Integer对象的地方,编译器幕后插入对Integer构造方法调用。
自动拆箱:一个包装类型,例如Integer被放到需要int类型的地方,则编译器幕后调用一个intValue方法。
注意:需要指定范型的地方,仍是不可改变的。
1.5.4 带有限制的通配符
为了解决范型的一些问题,Java使用 通配符:?
来解决这些问题,如下方法表示范型必须是Shape类或者其子类。
1 | // 该方法的集合参数的范型必须是Shape类或者Shape类的子类 |
1.5.6 类型界限
例如,想实现如下代码,编译器不能证明在第行对compareTo的调用是合法的。只有在T
是Comparable的情况下才能保证compareTo存在。可以使用类型界限
解决。在<>内,指定参数必须具有的性质。
错误的代码:
1 | public class FindMaxTest { |
正确代码:<T extends Comparable<? super T>>
:
区别:<T extends Comparable<? super T>>
:T必须继承Comparable接口或者父类继承了Comparable接口
<T extends Comparable<T>>
:T必须继承Comparable接口
T extends决定了传入对象的上限是T(只能是T或子类),<? super T>决定了下限是T(最少T实现了Comparable)
1 | public class FindMaxTest { |
1.5.7 类型擦除
Java中的范型是伪范型,只在源码中存在,只在源码中有效,有编译检查。一旦编译通过,Java的范型就会被擦除,成为原生类型,称为类型擦除。
1.5.8 范型的限制
由于类型擦除的原因,下面的每一个限制都必须遵守。
基本类型
基本类型不能用作类型参数,如GenericMemoryCell<int>
非法,必须使用包装类。
instanceof检测
insatanceof检测和类型转换只对原始类型(此处的GenericMemoryCell)进行。编译通过后,类型会被擦除,如下:
1 | public static void main(String[] args) { |
范型类型不能实例化
1 | T obj = new T() // 右边是非法的 |
不能创建范型数组
1 | T[] arr = new T[10]; // 右边是非法的 |
不能实例化参数化类型数组
1 | public static void ClassCastExceptionTest() { |
2 函数对象
定义一个只有方法而没有数据的类,然后把这个类的对象传递给别的方法,该对象通常叫做函数对象
2.1 简单实现
如下是一个传递Comparator类型的函数对象的实现
1 | public class GetTheMaxNum { |