以下是【西安文都IT】小编为大家编辑的内容,希望可以帮到大家!
先看下面一个例子,test1实例化一个List容器的时候没有指定泛型参数,当我们从容器中取出容器中的对象的时候我们必须小心翼翼,因为容器中的对象具有运行时的类型信息,这意味着你不能够将一个带有运行时类型信息的对象赋值给另一个类型,否则ClassCastException。
public void test1()throws Exception{
List list=new ArrayList();
list.add("float.lu");
list.add(1);
String name=(String)list.get(0);
int num=(Integer)list.get(1);
System.out.println(String.format("name[%s],num[%s]",name,num));
上面的代码没问题,可以很好地编译和运行通过,问题是我必须要事先很清楚地知道容器中的索引为0的对象是什么类型,索引为1的对象是什么类型,很显然,这在实际应用中是不切实际的,也是一种很不靠谱的做法,那么这个问题如何解决呢?泛型。
public void test2()throws Exception{
Listlist=new ArrayList();
list.add("a");
list.add(1)//1
引入泛型后,我们规定这个容器中只能存放类型为字符串类型的对象,好的,编译器可以识别泛型并帮我们检查编译错误,上面的代码中1处会出现编译错误。注意:泛型信息仅仅存在于编译期间,编译器可以通过泛型信息来对代码是否存在违规行为(编译错误)来进行检查,当编译器将代码编译为字节码之后,泛型信息将不复存在,然而对象的运行时信息仍然是有的,这就解释了为什么会出现ClassCastException。
public void test3()throws Exception{
Listlist=new ArrayList();
list.add("a");
list.add("b");
List _list=list;
ListintegerList=_list;
for(Integer item:integerList){
System.out.println(String.format("item[%s]",item));
上面这段代码编译没有问题,我们没有直接将泛型参数为String的容器赋值给泛型参数为Integer的容器,而是花了点点小心思,我们现将list赋值给_list,_list生命为可以存储任何类型,也就相当于无特定类型,而后我们又把_list赋值给integerList容器,integerList容器被声明为只能存储类型为Integer的对象。悲催的是这段代码在运行的时候报了ClassCastException,很明显,我们知道在迭代integerList容器中的对象的时候,这些对象是有运行时类型信息的,当带有String类型信息的对象赋值给Integer的时候显然就报错了。这一切看起来似乎没问题,符合逻辑,但是有一个问题我们还没有问:为什么会没有编译错误?
List被称作泛型类型。
List中的E被称为类型变量或类型参数。
List被称为参数化类型。
List中的String被称为实际类型参数。
List中的<>年typeof。
List被称为原始类型。
参数化类型可以引用一个原始类型对象,编译报告警告。
原始类型可以引用一个参数化类型对象,编译报告警告。
由上可知,ListintegerList=_list;可以通过编译。
同时编译之后参数化类型在运行时没有任何泛型信息,也就是为什么List.class和List.class是同一个东西。除了参数化类型之外,容器中的对象在运行的时候是有类型信息的,也就是为什么会ClassCastExcetion。关于泛型还有很多内容,这里不做多讲,文中有误也欢迎留言讨论。