您的位置:首页 > 编程语言 > Java开发

Java泛型 类型擦除

2015-06-08 16:37 471 查看
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) {
...
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 泛型 类型擦除