lt;数据结构与算法分析gt;读书笔记--利用Java5泛型实现泛型构
? 一、简单的泛型类和接口当指定一个泛型类时,类的声明则包括一个或多个类型参数,这些参数被放入在类名后面的一对尖括号内。 示例一: package cn.generic.example; public class GenericMemoryCell <AnyType>{ public AnyType read() { return storedValue; } void write(AnyType x) { storedValue=x; } private AnyType storedValue; } ? GenericMemoryCell有一个类型参数。在这个例子中对类型参数没有明显的限制,所以用户可以创建像GenericMemoryCell<String>和GenericMemoryCell<Integer>类声明内部,我们可以声明泛型类型的域和使用泛型类型作为参数或返回类型的方法。比如,类GenericMemoryCell<String>的write方法需要一个String类型的参数。如果传递其它参数那将产生一个编译错误。 ? 同时也可以声明接口是泛型的。 示例二: interface Comparable <AnyType>int compareTo(AnyType other); } ? 在Java5以前,Comparable接口不是泛型,而它的comparaTo()方法需要一个Object作为参数。于是,传递到compareTo方法的任何引用变量即使不是一个合理的类型也都会编译,而只是在运行时报告ClassCastException错误。在Java5中Comparable接口是泛型的。 ? 再比如以我目前用到的ORM框架MyBatis-Plus,其中的BaseMapper也是泛型接口,如下图所示: ? ? 二、自动装箱和拆箱什么是装箱和拆箱? 一句话概括:装箱就是自动将基本数据类型转换为包装器类型;拆箱就是? 自动将包装器类型转换为基本数据类型。 示例三(可与<数据结构与算法分析>读书笔记--实现泛型构件pre-Java5 中的示例三代码进行比较): class BoxingDemo { static main(String[] args) { GenericMemoryCell<Integer> m = new GenericMemoryCell<Integer>(); m.write(37); int val = m.read(); System.out.println("Contents are:"+val); } } ? 三、菱形运算符以上面的示例三代码中的GenericMemoryCell<Integer> m = new GenericMemoryCell<Integer>()来说,有些烦人,因为既然m是GenericMemoryCell<Integer>类型的,显然创建的对象也必须是GenericMemoryCell<Integer>类型的,任何其他类型的参数都会产生编译错误。Java7增加了一种新的语言特征,称为菱形运算符。 可以将()改写为new GenericMemoryCell<>() 示例四: ? new GenericMemoryCell<>(); m.write(5); m.read(); System.out.println("Contents are:"+val); } } ? ? ? 四、带有限制的通配符带限制的通配符,通常有两种表现形式:
? 使用原则可遵循PECS原则,其实就是四个单词的组合。 PECS — producer-extends,consumer-super 翻译过来就是生产者继承,消费者使用。 ? 五、泛型static方法有时候特定类型很重要,或许是因为下面几个原因: (1)特定类型用作返回类型; (2)该类型用在多于一个的参数类型中; (3)该类型用于声明一个局部变量。 ? 如果是这样,那么,必须要声明一种带很多类型参数的显式泛型方法。 ? 示例五: GenericStaticExample { static <AnyType> boolean contains(AnyType[]arr,AnyType x) { for(AnyType val:arr) if(x.equals(val)) return true; false; } } ? 上面显示是一种泛型static方法,该方法对值x在数组arr中进行一系列查找。通过使用一种泛型方法,代替使用Object作为参数的非泛型方法,当在Shape对象的数组中查找Apple对象时我们能够得到编译时错误。 ? 泛型方法特别像是泛型类,因为类型参数表使用相同的语法。在泛型方法中的类型参数位于返回类型之前。 ? ? 六、类型限界示例六(在一个数组中找出最大元的泛型static方法,以例说明类型参数的限界) TypeLimitExample { static <AnyType extends Comparable<? super AnyType>> AnyType findMax(AnyType[] arr) { int maxIndex = 0; for (int i = 0; i < arr.length; i++) if(arr[i].compareTo(arr[maxIndex])>0) maxIndex = i; arr[maxIndex]; } } ? 七、类型擦除泛型在很大程度上是Java语言中的成分而不是虚拟机中的结构。泛型类可以由编译器通过所谓的类型擦除过程而转为非泛型类。这样,编译器就生成一种与泛型类同名的原始类,但是类型参数都被删去了。类型变量由它们的类型限界来代替,当一个具有擦除返回类型的泛型方法被调用时,一些特性被自动插入。如果使用一个泛型类而不带泛型参数,那么使用的是原始类。 ? 类型擦除的一个重要推论是,所生成的代码与程序员在泛型之前所写的代码并没有太多的差异,而且事实上运行的也并不快。其显著优点在于,程序员不必把一些类型转换放到代码中,编译器将进行重要的类型检验。 ? 八、对于泛型的限制对于泛型类型有许多限制。由于类型擦除的原因,这里列出的每一个限制都是必须要遵守的。 1.基本类型基本类型不能用做类型参数。因此,GenericMemoryCell<int>是非法的。我们必须要使用包装类。 2.instanceof检测instanceof检测和类型转换工作只对原始类型进行。 (编辑:ASP站长网) |