本文延续上文,针对泛型程序设计,从以下方面进行讲解:
- 为何使用泛型程序设计
- 定义简单的泛型类
- 泛型方法
- 类型变量的限定
- 泛型代码和虚拟机
- 约束与局限性
- 泛型类型的继承规则
- 通配符类型
- 反射和泛型
4、泛型代码和虚拟机
这里内容比较多且杂,我们先概括几个主要思想:
- 虚拟机中没有泛型,只有普通的类和方法
- 所有的类型参数都用他们的限定类型转换
- 桥方法被合成来保持多态
- 为保持类型安全性,必要时插入强制类型转换
(1)当定义一个泛型类型时,系统会自动提供一个相应的原始类型。原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型。
(2)当程序调用泛型方法时,如果擦除返回类型,编译器就会插入相对应的强制类型转换。
5、约束与局限性
下面深入探讨使用Java泛型时需要考虑的一些限制,大多数限制都是由类型擦除引起的
5.1 不能用基本类型实例化类型参数
不能用类型参数代替基本类型,即没有Pair<double>
只有Pair<Double>
。这是因为类型擦除以后,Pair类含有Object类型的域,而Object不能存储double值。
5.2 运行时类型查询只适用于原始类型
虚拟机中的对象总有一个特定的非泛型类型,因此,所有的类型查询只产生原始类型。
5.3 不能创建参数化类型的数组
5.4 Varargs警告
5.5 不能实例化类型变量
不能使用像new T(···),new T[···]或者T.class这样的表达式中的类型变量。
5.6 泛型类的静态上下文中类型变量无效
5.7 不能抛出或捕获泛型类的实例
5.8 注意擦除后的冲突
6、泛型类型的继承规则
简单说来,就是无论S与T有什么联系,通常Pair<S>
和Pair<T>
没有什么联系。例如Manager类是Employee类的子类,但Pair<Employee>
和Pair<Manager>
并没有什么关系。
7、通配符类型
固定的泛型类型系统使用起来很不爽,因此出现了通配符类型。例如
Pair<? extends Employee>
表示任何泛型Pair类型,它的类型参数是Employee的子类,如Pair<Manager>
而不会是Pair<String>
。
7.1 通配符的超类型限定
通配符限定与类型变量限定十分相似,但还有一个附加功能,即可以指定一个超类型限定。例如
? super Manager
这个通配符限制为Manager的所有超类型。
7.2 无限定通配符
无限定通配符使用方式,如Pair<?>
。
7.3 通配符捕获
通配符捕获只有在有许多限制的情况下才是合法的,编译器必须能够确信通配符表达的时单个的、确定的类型。
下面,我们用一个例程来回顾前面讲述的概念们
package pair3;
public class PairTest3
{
public static void main(String[] args)
{
Manager ceo = new Manager("Gus Greedy", 800000, 2003, 12, 15);
Manager cfo = new Manager("Sid Sneaky", 600000, 2003, 12, 15);
Pair<Manager> buddies = new Pair<>(ceo, cfo);
printBuddies(buddies);
ceo.setBonus(1000000);
cfo.setBonus(500000);
Manager[] managers = { ceo, cfo };
Pair<Employee> result = new Pair<>();
minmaxBonus(managers, result);
System.out.println("first: " + result.getFirst().getName()
+ ", second: " + result.getSecond().getName());
maxminBonus(managers, result);
System.out.println("first: " + result.getFirst().getName()
+ ", second: " + result.getSecond().getName());
}
public static void printBuddies(Pair<? extends Employee> p)
{
Employee first = p.getFirst();
Employee second = p.getSecond();
System.out.println(first.getName() + " and " + second.getName() + " are buddies.");
}
public static void minmaxBonus(Manager[] a, Pair<? super Manager> result)
{
if (a == null || a.length == 0) return;
Manager min = a[0];
Manager max = a[0];
for (int i = 1; i < a.length; i++)
{
if (min.getBonus() > a[i].getBonus()) min = a[i];
if (max.getBonus() < a[i].getBonus()) max = a[i];
}
result.setFirst(min);
result.setSecond(max);
}
public static void maxminBonus(Manager[] a, Pair<? super Manager> result)
{
minmaxBonus(a, result);
PairAlg.swapHelper(result); // OK--swapHelper captures wildcard type
}
}
class PairAlg
{
public static boolean hasNulls(Pair<?> p)
{
return p.getFirst() == null || p.getSecond() == null;
}
public static void swap(Pair<?> p) { swapHelper(p); }
public static <T> void swapHelper(Pair<T> p)
{
T t = p.getFirst();
p.setFirst(p.getSecond());
p.setSecond(t);
}
}
时间: 2024-09-29 03:19:19