1.什么是泛型程序设计
2.为什么要使用泛型?
对于集合类如ArrayList,一个集合类实例中时可以存储任何Object类的对象的。如下代码所示:
List arrayList = new ArrayList();
arrayList.add("aaaa");
arrayList.add(100);
for(int i = 0; i< arrayList.size();i++){
String item = (String)arrayList.get(i);
Log.d("泛型测试","item = " + item);
}
显而易见,上面这段代码执行过程中是要报错的,因为集合实例中存储了一个非String类型的实例,这种强制的向下转型,是会报错的,当然,可以先进行instanceOf判断,然后再进行向下转型,但这样的代码显得太复杂了。在泛型编程下,上面的代码编程这样子
List<String> arrayList = new ArrayList<String>();
arrayList.add("aaaa");
arrayList.add(100); //报错
for(int i = 0; i< arrayList.size();i++){
String item = (String)arrayList.get(i);
Log.d("泛型测试","item = " + item);
}
在泛型的作用下,编译器会检查存入ArrayList实例中的对象的类型,所以这段代码在arrayList.add(100)的时候,就无法编译通过,因而不会再for循环中出现运行时异常的惨剧。
这就是泛型编程显而易见的好处。
2. 泛型编程只在编译期有效。在编译后,泛型会被擦除。代码如下:
List<String> stringArrayList = new ArrayList<String>();
List<Integer> integerArrayList = new ArrayList<Integer>();
Class classStringArrayList = stringArrayList.getClass();
Class classIntegerArrayList = integerArrayList.getClass();
if(classStringArrayList.equals(classIntegerArrayList)){
Log.d("泛型测试","类型相同");
}
上面的代码会正常的打出日志,为什么呢,因为在编译后,泛型被擦除,stringArrayList和integerArrayList都是ArrayList实例。
3.我们可以定义泛型类,泛型方法和泛型接口。
4.ClassName<SuperClass> 不是 ClassName<SubClass>的父类,不存在里氏替换。
5.泛型方法的定义和使用:
public class ArrayArg {
public static <T> T method1(T[] a){
return a[0];
}
public static void main(String[] args) {
String[] strs = {"1","2","3"};
ArrayArg.method1(strs);
}
}
6.泛型变量的限定
public class Test<T extends Comparable>{
}
上面定义的泛型类T的实际类型必须是一个实现了Comparable接口的类。
一个复杂的例子,可以看出来多泛型类和多限定泛型类的定义方法。
public class ArrayArg<T extends Comparable & DynamicInterface,V,M> {
public static <T> T method1(T[] a){
return a[0];
}
public static void main(String[] args) {
String[] strs = {"1","2","3"};
ArrayArg.method1(strs);
}
}
7.不能用基本类型实例化类型参数。
8.不能在类定义中实例化类型变量。
9.泛型类的静态方法和静态属性中类型变量是无效的。