JAVA泛型的局限性

首先我们需要清楚的一点是,jvm虚拟机中是不存在泛型的,只存在普通的方法和类,这是java泛型局限性的根本问题所在

泛型擦除

正确理解泛型概念的首要前提是理解类型擦除(type erasure)。 Java 中的泛型基本上都是在编译器这个层次来实现的。

在生成的 Java 字节代码中的泛型信息:

  1. 源码泛型所在位置的类型信息全部被删除了
  2. 在字节码的类, 字段, 方法的Signature属性中, 保留了泛型的类型信息,为反射提供了支持

所以说java字节码中存在的泛型信息只是部分信息(可以了解java的Type接口)。使用泛型类的时候加上的类型参数,会被编译器在编译的时候去掉。这个过程就称为类型擦除。如在代码中定义的 List<Object> 和 List<String> 等类型,在编译之后都会变成 List。JVM 看到的只是 List,而由泛型附加的类型信息对 JVM 来说是不可见的。Java 编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。

在分析JAVA的泛型问题的时候,都可以从泛型擦除进行考虑

开发人员在使用泛型的时候,很容易根据自己的直觉而犯一些错误。比如一个方法如果接收 List<Object> 作为形式参数,那么如果尝试将一个 List<String> 的对象作为实际参数传进去,却发现无法通过编译。虽然从直觉上来说,Object 是 String 的父类,这种类型转换应该是合理的。但是实际上这会产生隐含的类型转换问题,因此编译器直接就禁止这样的行为。

因为这样进行传递的时候,接收参数的一方会使用Object类型对List内的数据进行限制(这种限制是由java编译器进行的限制,JVM是不具有这样的能力的,java编译器帮我们在代码中加入了强制类型转换),而不是String类型,所以可能会导致你在接收参数的地方传入的类型为String类型,例如传入一个Integer类型,这样就会导致一个原本是用来保存String类型的list最终却存入了Integer,最终就可能导致类型转换异常。

 

桥方法

class MyString implements Comparable<String> {
    public int compareTo(String str) {        
        return 0;    
    }
} 

分析一下,还是从泛型擦除入手,当类型信息被擦除之后,上述类的声明变成了 class MyString implements Comparable。但是这样的话,类 MyString 就会有编译错误,因为在字节码中,没有实现接口 Comparable 声明的 int compareTo(Object) 方法。这个时候就由编译器来动态生成这个方法,这就是所谓的桥方法,在java字节码文件中我们能看到两个compareTo方法。

 

 

其他问题

  1. 不能用基本类型实例化参数类型
  2. 运行时类型判断只适用于原始类型,不适合带泛型的类型。比如if(a instanceof P<String>) 是错误的
  3. 不能创建参数化类型的数组,注意是不能创建,而不是不能声明。不能创建即不不能使用new P<String>[10]这种形式去创建,但是可以声明这种类型的数组P<String>[] p
  4. 不能实例化泛型对象
  5. 不能构造泛型数组,父类类型的数组转换为子类会出错
  6. 不能在异常中使用泛型
  7. 同一对象不同泛型类型之间不能相互转换,例如Employee<String>不能转换为Employee<Date>

上面的所有问题产生的原因,都可以通过泛型擦除来进行分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值