本文根据《Java核心卷轴》第十二章总结而来,更加详细的内容请查看《Java核心卷轴》
1. 泛型类型只能是引用类型,不可以使用基本数据类型。
2. 类型变量含义
E :集合K :关键字V :值T :任意类型
3. 泛型类
3.1 注意事项
类型变量声明放在类名的后面
3.2 示例
packagecom.BlueStarWei.generic;public class Pair{privateT first;privateT second;publicPair(T first, T second) {this.first =first;this.second =second;
}publicT getFirst() {returnfirst;
}public voidsetFirst(T first) {this.first =first;
}publicT getSecond() {returnsecond;
}public voidsetSecond(T second) {this.second =second;
}
}
4. 泛型方法
4.1 注意事项
类型变量放在修饰符的后面,返回类型的前面
4.2 示例
packagecom.BlueStarWei.generic;public classGenericMethodDemo{public static voidmain(String[] args) {
String s= getMiddle("Hello","world","Happy");
System.out.println(s);//World
}//T... 表示可以输入任意个数的参数
public static T getMiddle(T... a){return a[a.length / 2];
}
}
5. 类型变量的限定
5.1 T应该是绑定类型的子类型。T和绑定类型可以是类,也可以是接口。
5.2 一个类型变量可以有多个限定;如:T extends Comparable & Serializable
5.3 示例
packagecom.BlueStarWei.generic;public classBoundingTypeDemo {public static voidmain(String[] args) {
Integer[] a= new Integer[]{1,2,3,4};int max =getMax(a);
System.out.println(max);
}public static >T getMax(T[] a){if(a == null || a.length == 0) return null;
T max= a[0];for (int i = 0; i < a.length; i++) {if(max.compareTo(a[i]) < 0){
max=a[i];
}
}returnmax;
}
}
6. 运行时类型检查只适用于原始类型
6.1 校验情况
if(a instanceof Pair) //编译报错
if(a instanceof Pair) //编译报错
if(a instanceof Pair) //true
6.2 getClass返回的是原始类型
Pair a = new Pair("Hello", "World");
Pair b = new Pair(1,2);if(a.getClass().equals(b.getClass())){
System.out.println("true");//class com.ebao.gs.pol.nb.test.Pair
System.out.println(a.getClass());
}else{
System.out.println("false");
}
7. Java不支持泛型类型的数组
7.1 示例
Pair[] as = new Pair[10]; //编译报错
7.2 解决方案: 将参数化对象放入ArrayList
List> list = new ArrayList>();
8. 通配符的限定
8.1 子类型限定
8.1.1 Pair Extends Employee>不能调用setFirst方法,但是可以调用getFirst方法
? extendsEmployee getFirst()void setFirst(? extends Employee)
调用setFirst方法时,编译器只知道需要某个Employee的子类型,但是不知道具体什么类型。它拒绝传递任何特定类型(?不能用来匹配)。调用getFirst方法时,只是将getFirst的返回值赋值给一个Employee的引用,完全合法。
8.1.2 示例
public static void minMaxBonus(Manager[] manager, Pair
extends Manager>result) {if(manager.length == 0 || manager == null) return;
Manager minManager= manager[0];
Manager maxManager= manager[0];for (int i = 0; i < manager.length; i++) {if(manager[i].getBonus()
minManager=manager[i];if(manager[i].getBonus() >maxManager.getBonus())
maxManager=manager[i];
}
result.setFirst(minManager);//编译报错
result.setSecond(maxManager);//编译报错
Manager m =(Manager)result.getFirst();
System.out.println(m.getBonus());
8.2 超类型限定
8.2.1 Pair super Manager>可以调用setFirst方法,但是调用getFirst方法会返回Object对象(可以类型强转)
void setFirst(? superManager)? super Manager getFirst()
编译器不知道setFirst方法的确切类型,但是可以用任意Manager对象(或子类型)调用它。然而,如果调用getFirst方法,返回的对象类型就得不到保证。只能把它赋值给一个Object(但是可以类型强制转换)。
8.2.2 示例
public static void minMaxBonus(Manager[] manager, Pair
super Manager>result) {if(manager.length == 0 || manager == null) return;
Manager minManager= manager[0];
Manager maxManager= manager[0];for (int i = 0; i < manager.length; i++) {if(manager[i].getBonus()
minManager=manager[i];if(manager[i].getBonus() >maxManager.getBonus())
maxManager=manager[i];
}
result.setFirst(minManager);
result.setSecond(maxManager);
Manager m=(Manager)result.getFirst();
System.out.println(m.getBonus());
}
8.3 总结
通常而言:带有超类型限定的通配符可以向泛型对象中写入,带有子类型限定的通配符可以从泛型对象中读取。
8.4 附表(Manager类)
packagecom.ebao.gs.pol.nb.test;public classManager {privateLong id;privateString name;privateDouble bonus;publicManager(Long id, String name, Double bonus){super();this.id =id;this.name =name;this.bonus =bonus;
}publicLong getId() {returnid;
}public voidsetId(Long id) {this.id =id;
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}publicDouble getBonus() {returnbonus;
}public voidsetBonus(Double bonus) {this.bonus =bonus;
}
}
9.泛型的意义
减少强制类型转换的使用