JAVA泛型容器的类型检查

泛型容器是通过指定容器包含对象的类型,由编译器保证对象类型的正确性,在编译阶段就能检查出类型错误。如下列将List<Long>对象longList赋予一个List<GenericTest>对象gtList,会报编译错误。

public class GenericTest

{

public static List<Long> longList =
Arrays.asList (1L ,2L);

public static void main(String
args[]){

//下面这条语句编译会报错

List<GenericTest> gtList=longList ;

}

}

如果这只是在编译检查,那么我们是否可以绕过编译检查呢?我们先将List<Long>对象longList赋予一个raw
List变量rawList,然后再将这个rawList强制类型转换成List<GenericTest>类型。结果编译通过了,并且运行时也没有报错。我们成功地骗过了编译器。

public class GenericTest

{

public static List<Long> longList =
Arrays.asList (1L ,2L);

public static void main(String
args[]){

List rawList= longList;

//这个是可以编译通过,成功的骗过了编译器

List<GenericTest> gtList= rawList;

}

}

接着,如果我们使用List<GenericTest>类型的变量gtList,那会发生什么事。注意gtList引用的容器里面放的实际上是Long类型对象。这会发生什么事,会引用一段错误的内存吗?结果我们发现String result =
gtList.get(0).stringValue;语句正确地在运行时抛出 java.lang.ClassCastException异常。分析 main函数的字节码可知, 在该语句之前插入了类型转换检查字节码,导致了这个异常的抛出。看来Java设计者已经考虑到这一点,在泛型容器对象使用前加上了类型检查,防止这样的情况。

public class GenericTest

{

public static List<Long> longList =
Arrays.asList (1L ,2L);

public StringstringValue ="ss";

public static void main(String
args[]){

List rawList= longList;

//这个是可以编译通过,成功的骗过了编译器

List<GenericTest> gtList= rawList;

//会在运行时抛出 java.lang.ClassCastException

String result =gtList.get (0).stringValue;

}

}

字节码分析如下:

0 getstatic #28<variable/GenericTest.longList> //获得类变量longList, 并放入栈顶

3 astore_1  //将栈顶引用放入第一个本地变量 rawList

4 aload_1 //将第一个本地变量rawList,放入栈顶

5 astore_2 //将栈顶引用放入第二个本地变量tgList,这里我们可以看到将rawList赋值给tgList,没有任何类型检测,所以运行通过

6 aload_2

7 iconst_0

8 invokeinterface #43<java/util/List.get> count 2

13 checkcast #1 <variable/GenericTest> // 检测类型转换,当我们使用容器中对象时,会有类型检测,导致抛出java.lang.ClassCastException

16 getfield #37<variable/GenericTest.stringValue> // 获得实例属性,并放入栈顶

19 astore_3  //将栈顶引用放入第三个本地变量 result

20 return

时间: 2024-08-28 23:14:10

JAVA泛型容器的类型检查的相关文章

Java泛型 泛型类的类型擦除

任何一个泛型类型,都对应这个一个原始类型.原始类型的名字来源于带参数的泛型类型名去掉参数后的结果,并将类中用到类型变量的地方替换为类型变量的限定类型(如果没有限定类型就用Object).下面是一个来源于<Java核心技术 卷1>的例子: 类型擦除前: package generic; /** * @version 1.00 2004-05-10 * @author Cay Horstmann */ public class Pair<T> { private T first; pr

JAVA泛型中的类型擦除及为什么不支持泛型数组

一,数组的协变性(covariant array type)及集合的非协变性 设有Circle类和Square类继承自Shape类. 关于数组的协变性,看代码: public static double totalArea(Shape[] arr){ double total = 0; for (Shape shape : arr) { if(shape != null) total += shape.area(); } return total; } 如果给 totalArray(Shape[

java泛型 自限定类型

如SelfBoundGeneric<T extends SelfBoundGeneric<T>> 第一次看可能会非常疑惑,但是我现在只知道我第一次看的时候确实非常疑惑,但是具体怎么疑惑却不知道了. 那么这个泛型类的意思就是: 他接受一个类型参数T,而 T是继承SelfBoundGeneric<T> 的 就这么简单 所以 要想传递正确的 类型参数 给T 那么只能要传递类型只能是 class ClassName extends SelfBoundGeneric<Cla

ParameterizedType获取java泛型参数类型

https://blog.csdn.net/qq_18242391/article/details/54251947 前言 这两天在看以前写的ssh项目时,遇到一个问题就是封装的BaseDaoImpl抽象类,构造方法里面是这样写的. Class<T> clazz; public BaseDaoImpl() { ParameterizedType pt = (ParameterizedType)getClass().getGenericSuperclass(); clazz = (Class&l

Java泛型的实现:原理与问题

很久没写博客了,因为项目和一些个人原因.最近复习找工作,看书+回想项目后有一些心得,加上博客停更这么长时间以来的积累,很是有些东西可写.从今儿开始,慢慢把之前积累的东西补上来,方便以后查漏补缺. 先从最近的开始.昨天看到Java泛型相关的内容,有些疑惑,查资料之后发现这部分很有些有意思的东西,比如类型擦除带来的重写问题等等,一并记录在这篇文章里. 1. 泛型定义 看了很多泛型的解释百度百科,解释1,解释2,都不是我想要的"以用为本"答案(没讲明白泛型的作用或者说设计目的),这里我自己总

java 泛型深入理解

学习java开始接触到泛型是在容器的时候,如没有使用泛型 List list = new ArrayList(); list.add(1); list.add("1"); list.forEach(x-> System.out.println(x));//编译器不会报错,但是在输出list的时候要注意类型检查. 使用泛型 List<String> list = new ArrayList<String>(); list.add(1); list.add(&

赢在面试之Java泛型篇(十二)

139. Java中的泛型是什么 ? 使用泛型的好处是什么? 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数. 好处: 1.类型安全,提供编译期间的类型检测 2.前后兼容 3.泛化代码,代码可以更多的重复利用 4.性能较高,用GJ(泛型JAVA)编写的代码可以为java编译器和虚拟机带来更多的类型信息,这些信息对java程序做进一步优化提供条件. 140,Java的泛型是如何工作的 ? 什么是类型擦除 ?如何工作? 1.类型检查:在生成字节

Java:泛型基础

泛型 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚很多! 解决这种限制的三种方法: 1.多态:将方法的参数类型设为基类,那么该方法就可以接收从这个基类导出的任何类作为参数. class Primary{} //定义基类 class Test() { public void f(Primary p) {...} } 2.方法的参数使用接口:任何实现了该接口的类都可以满足该

从头认识java-13.11 对比数组与泛型容器,观察类型擦除给泛型容器带来什么问题?

这一章节我们继续类型擦除的话题,我们将通过对比数组与泛型容器,观察类型擦除给泛型容器带来什么问题? 1.数组 package com.ray.ch13; public class Test { public static void main(String[] args) { Fruit[] fruits = new Apple[5]; fruits[0] = new Apple(); fruits[1] = new Fuji(); fruits[2] = new Fruit(); } } cla