一、泛型的意义
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。
public class GenericTest {
public static void main(String[] args) {
List list = new ArrayList();
list.add("qqyumidi");
list.add("corn");
list.add(100);
for (int i = 0; i < list.size(); i++) {
String name = (String) list.get(i); // 1
System.out.println("name:" + name);
}
}
}
List默认的类型为Object类型,故上述代码编译正常,但运行时会出现“java.lang.ClassCastException”异常,此类错误编码过程中不易发现。
二、泛型定义
1.定义在类后面
紧跟类名后面
public class TestClassDefine<T, S extends T>{}
定义泛型 T, S, 且S 继承 T
2.定义在方法装饰符后面
紧跟修饰符后面(public)
public <T, S extends T> T testGenericMethodDefine(T t, S s){}
定义泛型 T, S, 且S 继承 T
三、实例化泛型
1.实例化定义在类上的泛型
第一声明类变量或者实例化时。例如
List<String> list;
list = new ArrayList<String>;
List<?> unknownList;
List<? extends Number> unknownNumberList;
List<? super Integer> unknownBaseLineIntgerList;
当赋值的类型不确定的时候,我们用通配符(?)代替。
注意:在Java集合框架中,对于参数值是未知类型的容器类,只能读取其中元素,不能向其中添加元素,
因为,其类型是未知,所以编译器无法识别添加元素的类型和容器的类型是否兼容,唯一的例外是NULL
第二继承类或者实现接口时。例如
public class MyList<E> extends ArrayList<E> implements List<E> {...}
2.实例化定义方法上的泛型
当调用范型方法时,编译器自动对类型参数(泛型)进行赋值,当不能成功赋值时报编译错误
当调用范型方法时,编译器自动对类型参数(泛型)进行赋值,当不能成功赋值时报编译错误
四、T和?的区别
T 是一种自定义类型,写在模板中将参数固定;多用在泛型定义中;
?是未知类型,泛指(就是通配符)一般用在泛型实例化时。
[1]ArrayList<T> al 指定集合元素只能是T类型
[2]ArrayList<?> al 集合元素可以是任意类型,这种没有意义,只是为了说明用法
[3]ArrayList<? extends E> al 泛型的限定:? extends E:接收E类型或者E的子类型。; ?super E:接收E类型或者E的父类型。
直接在测试函数中写下面代码:
List<?> list = new ArrayList<Object>();//能编译通过,但调用list.add()方法时会报编译错误;
List<T> tList = new ArrayList<Object>();//不能编译通过,找不到类型T