- 概述
在引入泛型之前,Java类型分为原始类型、复杂类型,其中复杂类型分为数组和类。jdk1.5引入范型后,一个复杂类型就可以在细分成更多的类型。
例如原先的类型List,现在在细分成List, List等更多的类型。
注意,现在List<Object>, List<String>
是两种不同的类型,
他们之间没有继承关系,即使String继承了Object。下面的代码是非法的
List<String> ls = new ArrayList<String>();
List<Object> lo = ls;
这样设计的原因在于,根据lo的声明,编译器允许你向lo中添加任意对象(例如Integer),但是此对象是 List<String>
,破坏了数据类型的完整性。所以上述代码是非法的。
在引入泛型之前,要在类中的方法支持多个数据类型,就需要对方法进行重载,在引入范型后,可以解决此问题(多态),更进一步可以定义多个参数以及返回值之间的关系。
例如:
public void write(Integer i, Integer[] ia);
public void write(Double d, Double[] da);
//泛型版本为
public <T> void write(T t, T[] ta);
泛型类:
//在类名后面声明元素类型。只要符合元素的命名规则都可以
public class Student<E> {
//在方法的后面声明元素的类型和实例
public void print(E e ){
System. out.println(e );
}
}
public class test {
public static void main(String[] args) {
//在创建类的时候声明其实例的存储类型(引用类型),是什么类型就必须是什么类型
Student <String> stu = new Student<String>();
stu.print("Hello");
//stu就只能存储String类型,要想存储Integer就必须重新生成实例
Student <Integer> stu1= new Student<Integer>();
stu1.print(20); //自动装箱
}
}
泛型类不能用在静态方法上,要在静态方法上使用方法必须自己声明泛型。
泛型方法:
//要一个方法不想和类的泛型类型保持一致。定义为泛型方法(静态方法必须为泛型方法)
public <AD> void method(AD ad ){
System. out.println(ad );
}
Student <String> stu = new Student<String>();
stu.print("Hello");
stu.method(100);
泛型的擦除:
把一个带泛型的实例赋值给一个不带泛型的实例时,会擦除其泛型信息,类型信息会提示到其上限类型…
在泛型的擦出中,如果声明的泛型没有自己继承,则提示到其上限类型为object.
java不允许创建泛型数组.可以使用带泛型参数值的类声明数组
List<Integer>[] iListArray;
new ArrayList<Integer>[10];//编译时错误
实现原理:
Java范型时编译时技术,在运行时不包含范型信息,仅仅Class的实例中包含了类型参数的定义信息。
类型参数在运行时并不存在。这意味着它们不会添加任何的时间或者空间上的负担.
一个泛型类被其所有调用共享:
List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());
它打印出true。因为一个泛型类的所有实例在运行时具有相同的运行时类(class),而不管他们的实际类型参数。
事实上,泛型之所以叫泛型,就是因为它对所有其可能的类型参数,有同样的行为;同样的类可以被当作许多不同的类型。作为一个结果,类的静态变量和方法也在所有的实例间共享。这就是为什么在静态方法或静态初始化代码中或者在静态变量的声明和初始化时使用类型参数(类型参数是属于具体实例的)是不合法的原因,必须为其提供自己单独的泛型。