java里程碑之泛型--深入理解泛型

所谓泛型,就是允许在定义类,接口,方法时使用类型形参,这个类型形参将在声明变量,创建对象,调用方法的时候动态的指定。JAVA5之后修改了集合中所有的接口和类,为这些接口和类都提供了泛型的支持。
关于泛型的底层,我们先来看看一段代码:
public class Test
{
	public static void main(String[] args)
	{
		List<String> strList = Lists.newArrayList();
		List<Integer> intList = Lists.newArrayList();
		System.out.println(strList.getClass() == intList.getClass());
	}
}

上面的代码new了2个list,然后判断这2个list的类是不是同一个?如果没有深入的了解过泛型,我们很容易以为上面的代码输出是false,但是运行上面的代码,实际输出是true。为什么呢?因为不管泛型的实际类型是什么,他们在运行时总是同样的类。比如下面的代码:
public class Test<T>
{
	public static void main(String[] args)
	{
		Test<String> test = new Test<>();
		List<String> strList = Lists.newArrayList();
		List<Integer> intList = Lists.newArrayList();
		System.out.println(strList.getClass() == intList.getClass());
	}
}
我们在编译之后,用反编译打开jar包看一下,代码的源码如下:
public class Test<T>
{
  public static void main(String[] args)
  {
    Test test = new Test();
    List strList = Lists.newArrayList();
    List intList = Lists.newArrayList();
    System.out.println(strList.getClass() == intList.getClass());
  }
}

从上面的2段代码我们得出一个结论,不管为泛型的类型形参传入哪一种类型实参,对于java来说,他们都被当成了同一个类来处理,在内存中也使用同一块内存空间。所以这里有2个注意的地方;
1),在静态方法,静态初始化块,静态变量的声明和初始化中都不允许使用类型形参。具体看下面的代码演示:
public class Test<T>
{
	//实例属性,实例方法是可以的,具体的T就是初始化这个类时候传入的形参。以下代码正常
	T name;
	public void test(T id)
	{
		
	}
	//静态属性和静态方法不可以用,这个时候没有实例初始化,也就是说这个T很有可能还没有传入。以下代码出错
	static T id;
	public static void test(T id)
	{
		
	}
}

2),在系统中并不会生成泛型类,所以instanceof运算符后不能使用泛型类。具体看下面的代码演示:
public class Test<T>
{
	public void test()
	{
		Collection<String> list = Lists.newArrayList();
		//下面代码正常
		if (list instanceof ArrayList)
		{


		}
		//下面代码报错,instanceof运算符后不能使用泛型
		if (list instanceof ArrayList<String>)
		{


		}
	}
}

总结:我们在使用泛型的时候,虽然程序只定义了一个List<E>的接口,但是在实际使用过程中我们可以传入随便的E的类型,这样子就可以产生无数多个List接口,只要为E传入不同的类型实参,系统就会多出一个新的List子接口。特别要注意的是,上面的任何一个子接口都不能被替换成一个固定的接口,比如List<String>不会替换成ListString,系统没有进行源代码复制,二级制代码中没有,磁盘和内存中都没有,也就是说这种子类我们只是可以这样子理解,但是在物理上根本不存在。
原文地址:https://www.cnblogs.com/LinkinPark/p/5232984.html