泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。Java语言引入泛型的好处是安全简单。
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。
定义泛型类,泛型方法,泛型接口的时候经常会碰见很多不同的通配符T,E,K,V,?等等很多通配符类型,
- ? 表示不确定的java类型
- * T (type)* 表示具体的一个java类型
- K V (key value) 分别代表java键值中的Key Value
- E (element) 代表Element
下面说说这些通配符类型的区别,大致分为两种:
通配符T,E,K,V
这种通配符表示赋值的都是具体的类型,符号只是一个标记,可以是任意的A,B,C,D…都可以,可以看个例子:
1.泛型类:
public class Parse<T> {
}
这里可以定义多个泛型参数,比如:
public class Parse<K,V> {
}
2.泛型方法
public <T> void print(T t){
System.out.println(t);
}
public <K,V> void print(K k,V v){
}
public <T> void print(List<T> t){
System.out.println(t);
}
3.泛型接口
interface Parse<K,V> {
void parse(K k, V v);
}
4.限定修饰符extends、super
public <T extends Map> void print(T t){
System.out.println(t);
}
当实例化泛型或调用泛型方法时,必须把T换成具体的类型,如果未指定,默认是Object类型,Object是所有的类的父类。
public static <T> void print(List<T> t){
System.out.println(t);
}
List<?> list =new ArrayList();
print(list);
List<String> list1 =new ArrayList();
print(list1);
List list2 =new ArrayList();
print(list);
通配符?
泛型中当赋值的类型不确定的时候,我们用通配符(?)代替了。
private List<?> list;
List<? extends Integer> list1;
List<? extends People> peopleList;
private List<? super People> peoples;
public void print(List<?> t){
System.out.println(t);
}
在Java集合框架中,对于参数值是未知类型的容器类,只能读取其中元素,不能向其中添加元素, 因为,其类型是未知,
所以编译器无法识别添加元素的类型和容器的类型是否兼容,唯一的例外是NULL.
T,Class<T>,Class<?>区别
T是一种具体的类,例如String,List,Map……等等,这些都是属于具体的类,这个比较好理解
* Class是什么呢,Class也是一个类,但Class是存放上面String,List,Map……类信息的一个类*。
如何获取到Class类呢,有三种方式:
1. 调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法。
例如:
List list = null;
Class clazz = list.getClass();
**2. 使用Class类的中静态forName()方法获得与字符串对应的Class对象。
**
例如:
Class clazz = Class.forName(“com.github.demo.domain.People”);
3.获取Class类型对象的第三个方法非常简单。如果T是一个Java类型,那么T.class就代表了匹配的类对象。
Class clazz = List.class;
* 那么问题来了?Class类是创建出来了,但是Class<T>和Class<?>适用于什么时候呢???*
使用Class<T>和Class<?>多发生在反射场景下,先看看如果我们不使用泛型,反射创建一个类是什么样的。
People people = (People) Class.forName("com.github.demo.domain.People").newInstance();
看到了么,需要强转,如果反射的类型不是People类,就会报
java.lang.ClassCastException错误。
Class<T>:
public static <T> T getInstance(Class<T> clazz) throws IllegalAccessException, InstantiationException {
return clazz.newInstance();
}
People people = getInstance(People.class);
Class<?>:
Class<?> class = Class.forName("com.github.demo.domain.People");