在运行时期,会将泛型去掉,生成的class文件中是不带泛型的,这个称之为泛型的擦除。
为什么要擦除呢?为了兼容运行时的类加载器。因为Java5及之前的类加载器是没有泛型的,识别不了泛型。
但是,一开始的问题又来了!!擦除后,如果你要获取数据的时候又要考虑类型转换的问题(数据的类型被擦除后,都变成了Object类型),那么,这个问题怎么解决呢?如果自己手动强转,那么之前做的就没有意义了。
解决方案就是泛型的补偿机制,这个补偿机制是在类加载器的基础上拓展的,这就意味着之前的类加载器的一套东西不需要改动,在运行时,通过getClass() 获取元素的类型进行自动的类型转换。不用使用者再进行强制转换了。
泛型擦除的体现:
public class GenericDemo2 {
public static void main(String[] args) {
List stringArrayList = new ArrayList();
List integerArrayList = new ArrayList();
Class classStringArrayList = stringArrayList.getClass();
Class classIntegerArrayList = integerArrayList.getClass();
System.out.println(classStringArrayList);
System.out.println(classIntegerArrayList);
if(classStringArrayList.equals(classIntegerArrayList)){
System.out.println(“类型相同”);
}
}
}
输出结果:
class java.util.ArrayList
class java.util.ArrayList
类型相同
通过上面的例子可以证明,在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
对此总结成一句话:泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。
四、泛型的使用
=======
1、泛型类
public class GenericDemo4 {
public static void main(String[] args) {
Tool tool = new Tool<>();
tool.setType(new Student());
Student student = tool.getType();
}
}
public class Tool {
private T t;
public T getType() {
return t;
}
public void setType(T t) {
this.t = t;
}
}
public class Student extends Person {
public Student() {
}
public Student(String name, int age) {
super(name, age);
}
}
public class Person implements Comparable {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person person) {
int temp = this.age - person.age;
return temp == 0 ? this.name.compareTo(person.name) : temp;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString()
{
return “Person{” +
“name=’” + name + ‘’’ +
“, age=” + age +
‘}’;
}
}
2、泛型方法
public class Tool {
private T t;
public T getType() {
return t;
}
public void setType(T t) {
this.t = t;
}
/**
将泛型定义在方法上
@param str
@param
*/
public void show(W str) {
System.out.println("show: " + str);
}
public void print(T str) {
System.out.println("print: " + str);
}
/**
当方法静态时,不能访问类上定义的泛型。如果静态方法使用泛型,只能将泛型定义在方法上
@param str
@param
*/
public static void method(Y str){
System.out.println("method: " + str);
}
}
public class GenericDemo5 {
public static void main(String[] args) {
Tool tool = new Tool<>();
tool.show(4);
tool.print(“haha”);
Tool.method(“hehehe”);
Tool.method(88);
}
}
3、泛型接口
public class GenericDemo6 {
public static void main(String[] args) {
InterImpl inter = new InterImpl();
inter.show(“abc”);
InterImpl2 inter2 = new InterImpl2();
inter2.show(“abc222”);
}
}
interface Inter {
void show(T t);
}
class InterImpl implements Inter {
@Override
public void show(String s) {
System.out.println(“show:” + s);
}
}
class InterImpl2 implements Inter {
@Override
public void show(T t) {
System.out.println(“show:” + t);
}
}
4、通配符的体现
public class GenericDemo7 {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList<>();
arrayList.add(“abc”);
arrayList.add(“haha”);
ArrayList arrayList2 = new ArrayList<>();
arrayList2.add(111);
arrayList2.add(222);
printCollection(arrayList);
printCollection(arrayList2);
}
/**
泛型的通配符:?
@param collection
*/
private static void printCollection(Collection<?> collection) {
Iterator<?> iterator = collection.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
5、泛型限定
? extends E:接受E类型或者其子类型对象 上限!
? super E: 接受E类型或者其父类型对象 下限!
一般存储元素的时候都是用上限,因为这样取出的都是按照上限类型来运算的,不会出现类型安全隐患。
ist2.add(222);
printCollection(arrayList);
printCollection(arrayList2);
}
/**
泛型的通配符:?
@param collection
*/
private static void printCollection(Collection<?> collection) {
Iterator<?> iterator = collection.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
5、泛型限定
? extends E:接受E类型或者其子类型对象 上限!
? super E: 接受E类型或者其父类型对象 下限!
一般存储元素的时候都是用上限,因为这样取出的都是按照上限类型来运算的,不会出现类型安全隐患。