LinkinPark
当你的才华撑不起你野心时,那么请潜下心继续学习,心无旁骛,愿多年以后你们我都能成为自己想象的模样。
在严格的泛型代码里,带泛型声明的类总应该带着泛型参数。但是为了和古老的java代码保持一致,也就是说为了向下兼容,也允许在使用带泛型声明的类时不指定实际的类型参数。如果没有为这个泛型类指定实际的参数类型,则该类型参数就被称为rawtype,也就是原始类型。比如说我们声明一个list的时候如果没有传入实际的泛型参数,我们可以抑制警告,这个时候这个警告抑制的就是rawtype,默认是声明该类型参数时指定的第一个上线类型。


  • 什么是泛型的擦除?
当把一个具体泛型信息的对象赋值给另外一个没有泛型信息的变量时,所有尖括号之间的类型信息都将被扔掉。比如说将一个List<String>类型赋值给一个list,这个时候原来的这个List<String>集合的类型就变成了类型参数的上限了,也就是Object了。看一下代码:
public class Test<S>
{
	S name;


	public S getName()
	{
		return name;
	}


	public void setName(S name)
	{
		this.name = name;
	}


	public static void main(String[] args) throws Exception
	{
		Test<Integer> test1 = new Test<>();
		test1.setName(1);
		Test test2 = test1;
		//泛型的擦除,编译过程中丢失了具体的参数类型
		Integer name2 = (Integer) test2.getName();
		//运行时候对象的类型没变,擦除只是发生在编译阶段
		System.out.println(test2.getName().getClass());
	}
}


  • 什么是泛型的转换?

从逻辑上来看,List<String>是List的子类,如果直接把一个List对象赋值给一个List<String>对象应该引起编译错误,但实际上不会。但是由于这里典型的擦除,所以我们在后面使用这个没有类型的List在做操作的时候,我们将它再次赋值给你另外一个有实际类型参数的list,这个时候很容易就会引起ClassCastException。同时这也算是给了我们一种折中的方案,就是说我们可以绕开泛型,比如我原来的是小范围的类型,那么我先将泛型移除,然后就变成了一个大范围的类型,然后我们在向下赋值,再次赋值给一个小范围的类型,编译过程都都不会报错,但是实际运行时候很容易发生类型转换异常,这也就是我们说的泛型的转换。所以我们以后还是应该养成好的习惯,每次在使用有泛型声明的类和接口时都应该传入实际的参数类型。
public class Test<S>
{
	S name;


	public S getName()
	{
		return name;
	}


	public void setName(S name)
	{
		this.name = name;
	}


	public static void main(String[] args) throws Exception
	{
		List<Integer> list = new ArrayList<>(2);
		list.add(1);
		list.add(2);
		List list1 = list;
		List<String> list2 = list1;
		System.out.println((String)list2.get(0));
	}
}


posted on 2015-10-22 17:35  LinkinPark  阅读(438)  评论(0编辑  收藏  举报