对Java泛型擦除的补偿

对Java泛型擦除的补偿对 Java 泛型擦除的补偿文章目录对 Java 泛型擦除的补偿一 泛型的擦除 1 1 为泛型类设置边界 可以设置多个边界 就可以通过泛型对象调用边界的方法二 擦除的补充 2 1 对 instanceof 的补充 引入类型标签 使用动态的 isInstance 2 2 对泛型 newT 对补偿 newInstance 显式工厂 2 3 创建泛型数组 Array newInstance 一 泛型的擦除在泛型代码内部 无法获得任何有关泛型参数类型的信息 Java 泛型是使用擦除实现的 这意味着

对Java泛型擦除的补偿

一、泛型的擦除

在泛型代码内部,无法获得任何有关泛型参数类型的信息。

Java泛型是使用擦除实现的,这意味着当你在使用泛型时,任何具体的类型信息都被擦除了,唯一知道的就是在使用一个对象。

1.1 为泛型类设置边界(可以设置多个边界),就可以通过泛型对象调用边界的方法

public class HasF { 
    public void f(){ 
    System.out.println("HasF.f()"); } } class Manipulator<T extends HasF>{ 
    private T t; public Manipulator(T t){ 
    this.t = t; } public void manipulate(){ 
    t.f(); } } // 可以自行擦除,创建出没有泛型的类 class Manipulator2{ 
    private HasF obj; public void manipulate(){ 
    obj.f(); } } 

当希望代码能够跨多个类工作时,使用泛型才有所帮助。例如,返回T的方法,那么泛型就有所帮助,因为它们之后将返回确切的类型:

class Manipulator3<T extends HasF>{ 
    private T t; public Manipulator3(T t){ 
    this.t = t; } public T getT(){ 
    return t; } } 

二、擦除的补充

任何在运行时需要知道确切类型信息的操作都无法工作

public class Erased<T>{ 
    private final int SIZE = 100; public static void f(Object arg){ 
    if(arg instanceof T){ 
   } // error T var = new T(); // Error T[] array = new T[SIZE]; // Error T[] array = (T)new Object[SIZE]; // Unchecked warning  } } 

2.1 对instanceof的补充:引入类型标签,使用动态的isInstance()

class Building{ 
   } class House extends Building{ 
   } public class ClassTypeCapture<T> { 
    Class<T> kind; public ClassTypeCapture(Class<T> kind){ 
    this.kind = kind; } public boolean f(Object arg){ 
    return kind.isInstance(arg); } public static void main(String[] args) { 
    ClassTypeCapture<Building> ctt1 = new ClassTypeCapture<>(Building.class); System.out.println(ctt1.f(new House())); System.out.println(ctt1.f(new Building())); } } 

2.2 对泛型new T()对补偿:newInstance()、显式工厂

使用下面的方式,如果实际类型没有默认构造器,将会运行时出错。

class Employee{ 
   } public class ClassAsFactory<T> { 
    T x; public ClassAsFactory(Class<T> kind){ 
    try { 
    x = kind.newInstance(); } catch (InstantiationException|IllegalAccessException e) { 
    throw new RuntimeException(e); } } public static void main(String[] args) { 
    ClassAsFactory<Employee> fe = new ClassAsFactory<>(Employee.class); System.out.println("ClassAsFactory 
   
     succeed" 
   ); try { 
    // Integer 没有默认对构造器, 因此会失败 ClassAsFactory<Integer> fi = new ClassAsFactory<>(Integer.class); }catch (Exception e){ 
    System.out.println("ClassAsFactory 
   
     failed" 
   ); } } } 

通过显式工厂,可以获得编译期检查:

interface FactoryI<T>{ 
    T create(); } class Foo2<T>{ 
    private T t; public <F extends FactoryI<T>> Foo2(F f){ 
    t = f.create(); } } class IntegerFactory implements FactoryI<Integer>{ 
    @Override public Integer create() { 
    return new Integer(0); } } class Widget{ 
    public static class Factory implements FactoryI<Widget>{ 
    @Override public Widget create() { 
    return new Widget(); } } } public class FactoryConstraint { 
    public static void main(String[] args) { 
    new Foo2<Integer>(new IntegerFactory()); new Foo2<Widget>(new Widget.Factory()); } } 

2.3 创建泛型数组:Array.newInstance()

没有任何方式可以推翻底层的数组类型,它只能是Object[]

class Generic<T>{ 
   } public class ArrayOfGeneric { 
    static final int SIZE = 100; static Generic<Integer>[] gia; public static void main(String[] args) { 
    // java.lang.ClassCastException // gia = (Generic 
   
     []) new Object[SIZE]; 
    gia = (Generic<Integer>[])new Generic[SIZE]; System.out.println(gia.getClass().getSimpleName()); } } 

泛型T[] ,因为有了擦除,数组的运行时类型就只能是Object[]。在下面代码中调用rep() 将报错:

public class GenericArray<T> { 
    private T[] array; public GenericArray(int sz){ 
    array = (T[]) new Object[sz]; } public T get(int index){ 
    return array[index]; } public T[] rep(){ 
    return array; } public static void main(String[] args) { 
    GenericArray<Integer> gai = new GenericArray<>(10); // java.lang.ClassCastException,因为实际运行的类型是Object[] Integer[] ia = gai.rep(); } } 

尝试将Object[]转换成T[],将在运行时产生异常。没有任何方式可以推翻底层的数组类型,它只能是Object[]

public class GenericArray2<T> { 
    private Object[] array; public GenericArray2(int sz){ 
    array = new Object[sz]; } public void put(int index, T item){ 
    array[index] = item; } public T get(int index){ 
    return (T) array[index]; } public T[] rep(){ 
    return (T[]) array; } public static void main(String[] args) { 
    GenericArray2<Integer> gai = new GenericArray2<>(10); for (int i = 0; i < 10; i++) { 
    gai.put(i, i); } for (int i = 0; i < 10; i++) { 
    System.out.print(gai.get(i) + " "); } System.out.println(); // java.lang.ClassCastException Integer[] ia = gai.rep(); } } 

使用Array.newInstance() 创建泛型的数组:

public class GenericArrayWithTypeToken<T> { 
    private T[] array; public GenericArrayWithTypeToken(Class<T> type, int sz){ 
    array = (T[]) Array.newInstance(type, sz); } public void put(int index, T item){ 
    array[index] = item; } public T[] rep(){ 
    return array; } public static void main(String[] args) { 
    GenericArrayWithTypeToken<Integer> gai = new GenericArrayWithTypeToken<>(Integer.class, 10); Integer[] ia = gai.rep(); System.out.println(ia); } } 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/177149.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午8:11
下一篇 2026年3月26日 下午8:12


相关推荐

  • 程序员必看:5个Cursor使用技巧,让你的AI编程效率翻倍

    程序员必看:5个Cursor使用技巧,让你的AI编程效率翻倍

    2026年3月15日
    2
  • 备份从android到ios系统文件,如何将音乐从安卓设备转移到iOS设备中「建议收藏」

    备份从android到ios系统文件,如何将音乐从安卓设备转移到iOS设备中「建议收藏」这几天,小编刚从Android手机切换到iPhone,可是Android手机上还有很多音乐文件没有保存下来,这时候该怎么处理呢?好在,小编发现了一款神器——iMazing,它可以帮助我们顺利的转移各种文件,音乐文件也是不在话下,下面就和小编一起来看看具体该怎么操作吧!图1iPhone将Android手机中的音乐文件转移到电脑中如果大家使用的是Mac电脑,需要到Android官方网站下载Andor…

    2026年1月15日
    4
  • idea激活服务器 3月最新注册码

    idea激活服务器 3月最新注册码,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月15日
    43
  • openclaw入门教程自用

    openclaw入门教程自用

    2026年3月13日
    2
  • 图解springmvc 执行流程

    图解springmvc 执行流程核心对象DispatcherServlet核心控制器负责请求,响应,数据的分发。HandlerMapping处理器映射器,负责到controller中,找到对应的方法,返回给核心控制器。HandleAdapter处理适配器,将handle找到的方法执行,执行结果,即ModelAndView数据和视图返回给核心控制器。HttpMessageConvertor消息转换器,数据类型的转换,如日期…ViewResolver视图解析器,核心控制器调度视图解析器,视图解析器,返回视图。核心控制

    2022年6月28日
    33
  • visual studio code适合什么语言_将当前运行的配置备份成初始配置

    visual studio code适合什么语言_将当前运行的配置备份成初始配置VSCode是一款非常好用的编辑器(或者IDE),具有很好的可扩展性,功能比较强大,占用的系统资源也适中,启动速度较快,而且支持全平台,比较适合作为Python开发用的IDE。本文针对Linux(主要是Ubuntu,其他发行版类似),整合一些Python开发相关的配置,仅供刚入坑Linuxer参考。一、VSCode与其他编辑器(或IDE)的比较(1)VSCode与Atom的比较:Atom是一款由g…

    2022年8月25日
    9

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号