JAVA 泛型之类型擦除

书写本文原因

书写本文的原因,由于在项目中看到了类似如下逻辑的代码

JAVA 泛型之类型擦除_第1张图片

出现这样的逻辑原因,数据库使用的是postgresql, 对应字段为jsonb,字段中有对应key的value为另外一表的主键的列表。 此字段对应java的map类型(列表值较小时起始对应的是Integer类型)。大多数为了方便直接强转List。 起初以为强转会出问题,写了测试代码,发现此写法能正常运行。只不过存在其他问题。

存在问题

1:类似例子中注释掉的remove方法, 原因remove 方法调用的是equals方法,首先进行类型的判断, 类型判断不想等,也就是移除一定会失败

2:获取list中的任意对象赋值给变量, 原因不能将Integer对象赋值给Long变量

解析

强转正常的原因, java的泛型在运行时其实泛型类型是擦除掉了,也就是说泛型的作用其实就存在于编译期. 上述代码在运行期仅仅会检测其是否属于list,而不会检测其list中的具体对象的类型,即上述的强转,无论泛型的类型是什么均不会出现问题.

泛型擦除解析

JAVA 泛型之类型擦除_第2张图片JAVA 泛型之类型擦除_第3张图片

上述两张图分别为源码,以及编译生成的部分字节码, 我们可以关注下add方法以及get方法, add方法的方法描述为(Ljava/lang/Object;)Z  接收参数为Object 返回值类型为boolean值, 而java源码中的方法的参数确是E 泛型. 看get方法的描述符(I)Ljava/lang/Object 方法的返回值类型是Object类型. 我们可以看出,泛型源码经过编译器其实转换为了Object的类型.这就是泛型类型擦除的原因.  另外的问题来了, 我们调get方法,既然是返回的Object为什么我们不用显式的强转,从上面的字节码中可以看到另外一个关键词 24: checkcast, 对应的类型是java/lang/String, 也就是编译器会自动帮我们加上一个强转的处理。

思考

既然泛型类型在运行期泛型类型已经被擦除了,如果我们运行期添加其他类型的对象到List中会出现什么情况。可以手动测测使用反射往List对象中添加其他的类型变量。 这种测试本没有什么太大意义,但是可以增加对泛型变量运行期类型擦除的理解.

你可能感兴趣的:(JAVA)