1.泛型类的类型擦除
任何一个泛型类型,都对应这个一个原始类型。原始类型的名字来源于带参数的泛型类型名去掉参数后的结果,并将类中用到类型变量的地方替换为类型变量的限定类型(如果没有限定类型就用Object)。下面是一个来源于《Java核心技术 卷1》的例子:
类型擦除前:
package generic;
/**
* @version 1.00 2004-05-10
* @author Cay Horstmann
*/
public class Pair<T>
{
private T first;
private T second;
public Pair() { first = null; second = null; }
public Pair(T first, T second) { this.first = first; this.second = second; }
public T getFirst() { return first; }
public T getSecond() { return second; }
public void setFirst(T newValue) { first = newValue; }
public void setSecond(T newValue) { second = newValue; }
}
类型擦除后:
package generic;
/**
* pair<T>类型擦出后的版本,即pair<T>得原始类型;
* 擦除规则是,删除类名后面的类型变量,并将类中用到
* 类型变量的地方替换为类型变量的限定类型(
* 如果没有限定类型就用Object)
* @author yuncong
*
*/
public class Pair {
private Object first;
private Object second;
public PairOrigin() { first = null; second = null; }
public PairOrigin(Object first, Object second) { this.first = first; this.second = second; }
public Object getFirst() { return first; }
public Object getSecond() { return second; }
public void setFirst(Object newValue) { first = newValue; }
public void setSecond(Object newValue) { second = newValue; }
}
针对泛型类的测试,有两个辅助类:
package generic;
public class Person extends Animal {
private String name;
public Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
package generic;
public class Student extends Person {
private String studentNumber;
public Student(String name, String registrationNumber) {
super(name);
this.studentNumber = registrationNumber;
}
public String getStudentNumber() {
return studentNumber;
}
public void setStudentNumber(String studentNumber) {
this.studentNumber = studentNumber;
}
@Override
public String toString() {
return "Student [studentNumber=" + studentNumber + ", name="
+ getName() + "]";
}
}
下面的测试说明了调用Pair<T>的getFirst()方法的实际过程:
package generic;
public class Test3 {
public static void main(String[] args) {
Pair<Person> pair = new Pair<Person>(new Person("li"),
new Person("wang"));
/**
* 因为Pair<T>在类型擦除之后,它的
* getFirst()方法返回类型其实是Object,
* 所以这里其实经历了两步:
* 1.对原始方法pair.getFirst()的调用
* 2.将返回的Object类型强制转化为Person类型
*/
Person person = pair.getFirst();
/**
* 关于上面这个测试,下面的知识是必须明白的
*/
// 将父类型赋值给为子类型,必须需要强制类型转化
Person person2 = new Person("yuncong");
Person person3 = new Student("yuncong", "1");
Student student = (Student) person3;// ok
// 如果父类型的实际类型不是子类型,就会报造型错误
Student student1 = (Student) person2;// error
}
}
下面的测试说明参数化类型是它的原始类型的子类型:
package generic;
public class Test4 {
public static void main(String[] args) {
Pair<Person> personPair = new Pair<Person>();
// 可以将参数化类型转化为它的原始类型
Pair pair = personPair;
Building building = new Building("dingxin");
/**
* ok, 可以将building传给pair;
* 失去了泛型程序设计提供的附加安全性(类型检查)
*/
pair.setFirst(building);
Person person = (Person) pair.getFirst(); // 造型错误
/**
* The method setFirst(Person) in the type Pair<Person>
* is not applicable for the arguments (Building)
*/
// error,不能将building传给personPair,泛型程序设计提供的类型安全
personPair.setFirst(building);
}
}
2.泛型方法的类型擦除
泛型方法的类型擦除规则是,去掉方法的类型变量,方法中用到类型变量的地方替换为类型变量的限定类型(如果没有限定类型就用Object)。
如果有这样一个泛型方法:
public static <T extends Person> T getTallestPerson(T[] a) {
...
}
类型擦除后变为下面这个样子:
public static Person getTallestPerson(Person[] a) {
...
}