Java泛型:类型擦除
Posted 流楚丶格念
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java泛型:类型擦除相关的知识,希望对你有一定的参考价值。
文章目录
问题导引
这个例子里,定义了两个List集合,不过一个是List泛型类型的,只能存储整数;一个 是List泛型类型的,
只能存储字符串。最后我们通过list1对象和list2对象的 getClass()方法获取他们的类的信息,结果发现结
果为true。说明泛型类型String和 Integer都被擦除掉了,只剩下原始类型。
例如如下代码:
package com.fanxing;
import java.util.ArrayList;
import java.util.List;
public class FanTest
public static void main(String[] args)
List<Integer> list1 = new ArrayList<Integer>();
List<String> list2 = new ArrayList<String>();
System.out.println(list1.getClass() == list2.getClass());
他的运行结果是true:
啊??????啊这??????这是啥?
别慌,这就是类型擦除,下面咱们来详细查看一下:
类型擦除概念
泛型是java1.5版本才引进的概念,在这之前没有泛型,但是,泛型代码能够很好的和之前版本的代码兼容,原因是泛型只存在代码编译阶段,在进入JVM 之前,泛型相关的信息会被擦除掉,我们称之为类型擦除
类型擦除应用场景
需要值得注意的一点是:类型擦除后保留的原始类型
原始类型就是擦除去了泛型信息,最后在字节码中的类型变量的真正类型,无论何时定义一个泛型,相应的原始类型都会被自动提供,类型变量擦除,并使用其限定类型(无限定的变量用Object)替换。
看下面两个例子理解一下:
案例:原始类型被Object替换
代码如下(不能运行,就是看一下这个特性)
class Pair<T>
//原始类型就是Object
private T value;
public T getValue()
return value;
public void setValue(T value)
this.value = value;
public static void main(String[] args)
Pair pair = new Pair();
pair.setValue();//调用setter方法能看到参数类型是 Object:setValue(Object) ctrl+鼠标放到setValue()中能看到setValue(Object)
因为在Pair中,T是一个无限定的类型变量,所以用Object代替,其结果就是一个普通的类,如同泛型加入Java之前就已经实现了。在程序中可以包含不同类型的Pair, 如Pair擦除类型后他们就成了原始的Pair 类型,原始类型都是Object。
案例:原始类型被限定类型替换
我们可以用extends设置上届
class Pair<T extends Comparator>
//原始类型就是Comparator
private T value;
public T getValue()
return value;
public void setValue(T value)
this.value = value;
public static void main(String[] args)
Pair pair = new Pair();
pair.setValue();//调用setter方法能看到参数类型是 Comparator:setValue(Comparator)
这里相应的原始类型都会被自动提供了,原始类型就用第一个边界的类型替换,也就是Comparator
类型擦除的限制
无法利用同一泛型类的实例区分方法签名
例如下面代码,就会报错:
public class Erasure
//虽然泛型实例不同,但是由于类型擦除后是同一字节码(类型擦拭之后,就都是 List了),因此不能 用于区分方法签名
public void test(List<String> list)
System.out.println("String");
public void test(List<Integer> list)
System.out.println("Integer");
虽然泛型实例不同,但是由于类型擦除后是同一字节码(类型擦拭之后,就都是 List了),因此不能 用于区分方法签名 +
泛型类的静态变量是共享的
例如下面代码:
class StaticTest
public static void main(String[] args)
System.out.println(GT.var);
GT<Integer> gti = new GT<>();
gti.var = 1;
System.out.println(GT.var);
GT<String> gts = new GT<>();
gts.var = 2;//泛型参数不同,但是共享类的静态成员
System.out.println(GT.var);
class GT<T>
public static int var = 0;
public void nothing(T x)
结果如下所示,泛型参数不同,但是共享类的静态成员:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2YvBYisN-1659850950876)(…/AppData/Roaming/Typora/typora-user-images/image-20220807133710734.png)]
类型擦除的特征
-
所有泛型类的类型参数在编译时都会被擦除,虚拟机运行时中没有泛型,只有普通类和普通方法,从这一点上来说,Java中的泛型从某种程度上是一种语法糖
-
Java泛型不支持基本类型 例如: short int double等
-
在泛型代码内部,无法获得任何有关泛型参数类型的信息,如果传入的类型参数为T,那么在泛型代码内部你不知道T有什么方法,属性,关于T的一切信息都丢失了
-
创建泛型对象时请指明类型,让编译器尽早的做参数检查
-
不要忽略编译器的警告信息,那意味着潜在的ClassCastException等着你
-
Java的泛型类型不能用于new构建对象(也不能用于初始化数组).泛型不能用于显性地引用运行时类型的操作之中,例如转型,instanceof和new操作(包括new一个对象,new一个数组),因为所有关于参数的类型信息都在运行时丢失了,所以任何在运行时需要获取类型信息的操作都无法进行工作。
例如下面测试,系统不知道T的信息,他根本不能初始化[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dbDMda04-1659850950877)(…/AppData/Roaming/Typora/typora-user-images/image-20220807134046789.png)]
以上是关于Java泛型:类型擦除的主要内容,如果未能解决你的问题,请参考以下文章