泛型
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除 。泛型擦除
泛型一般有三种使用方式:泛型类、泛型接口、泛型方法。
public class Type<E>{}
public interface Interface<E> {}
public <E> E test(E e) {
return e;
}
<? extends T>和<? super T>的区别 【了解】
分两种情况:
1. 作为容器时 【了解】
<? extends T>
没有意义,只能存null
<? super T>
可以放它本身和其子类类型,可以存null
public static void main(String[] args) {
SuperMan man = new SuperMan();
Person p = new Person("", 1);
Student s = new Student("", 1);
List<? extends Person> list = new ArrayList();
// list.add(man);
// list.add(p);
// list.add(s);
// list.add(1);
list.add(null);
List<? super Person> list1 = new ArrayList();
// list1.add(new Object());
// list1.add(man);
list1.add(p);
list1.add(s);
list1.add(null);
// list1.add(1);
}
public class Person extends SuperMan implements Comparable{
private String name;
private int age;
//省略部分代码
}
class Student extends Person{
public Student(String name, int age) {
super(name, age);
}
}
class SuperMan {
}
2. 作为方法参数时
<? extends T>
支持其本身类型及其子类类型,也就是设置上限。
<? super T>
支持本身类型及其父类类型,也就是设置下限。
public static void main(String[] args) {
List<Object> listObj = new ArrayList();
List<SuperMan> listMan = new ArrayList();
List<Person> listPson = new ArrayList();
List<Student> listStu = new ArrayList();
// ? extends Person
// test(listObj);
// test(listMan);
test(listPson);
test(listStu);
// ? super Person
test1(listObj);
test1(listMan);
test1(listPson);
// test1(listStu);
}
public static void test(List<? extends Person> list) {
}
public static void test1(List<? super Person> list) {
}
常用的通配符为: T,E,K,V,?通配符介绍
-
?
表示不确定的 java 类型 -
T
(type) 表示具体的一个java类型 -
K V
(key value) 分别代表java键值中的Key Value -
E
(element) 代表Element
泛型的使用限制
1. 无法使用基本数据类型
List<int> list = new ArrayList<>(); // 编译时错误
2. 无法创建泛型参数类型的实例
public <E> void test(E e) {
E e1 = new E(); // 编译时错误
}
但是可以通过反射来创建对象
public <E> void test(E e) {
E e1 = e.getClass().newInstance();// 正确
}
3. 不能为static
字段(属性)声明为泛型类型
class Test<T>{
private static T name; // 编译错误
private T age; // 正确
}
4. 无法使用泛型类型进行强制类型转换或者 instanceof
List<Integer> li = new ArrayList<>();
List<Number> ln = (List<Number>)li; //编译错误
除非使用无界符号(?
)才可以强制转换
List<?> li = new ArrayList<>();
List<Number> ln = (List<Number>)li;
// 或者
List<Integer> li = new ArrayList<>();
List<?> ln = (List<?>)li;
在某种情况下,编译器知道泛型类型始终有效并允许强制类型转换
List<String> li = new ArrayList<>();
ArrayList<String> ln = (ArrayList<String>)li;
instanceof
public <E> void test(List<E> list) {
if(list instanceof ArrayList<String>) {} //编译错误
}
运行时是不跟踪参数类型的,所以无法区分泛型类型。可以使用无界符号
public <E> void test(List<E> list) {
if(list instanceof ArrayList<?>) {} //正确
}
5. 无法创建泛型类型的数组
List<String>[] lists = new ArrayList<String>[2]; //编译时错误
将不同类型元素插入到数组中:
Object[] objs = new String[2];
objs[0] = "s";
objs[1] = 1; // java.lang.ArrayStoreException
使用集合进行相同的操作
Object[] obs = new List<String>[2]; // 编译错误
obs[0] = new ArrayList<String>();
obs[1] = new ArrayList<Integer>();
6. 无法创建、捕获或者抛出泛型类型异常
泛型不能直接或间接扩展Throwable
类。
class Ex<T> extends Exception{} // 编译错误
class Exc<T> extends Throwable{} // 编译错误
无法捕获泛型类型实例
public <T extends Exception> void test() {
try {
}catch(T t) { // 编译错误
}
}
但是可以在throws
子句中出现文章来源:https://uudwc.com/A/k9ZaB
public <T extends Exception> void test() throws T{}
7. 泛型擦除到原生类型的方法无法重载
因为泛型擦除后,方法的签名一样。文章来源地址https://uudwc.com/A/k9ZaB
public void test(List<String> list) {} //编译错误
public void test(List<Integer> list) {} // 编译错误