Java集合有个缺点:当我们把这个元素存入这个集合之后,集合就会忘了这个元素的数据类型,当我们取出的时候就会变成Object类型。为弥补这一缺点有了泛型。
泛型就是在定义这个类或者接口的时候就指定类型形参。
泛型语法:在接口集合接口,集合类后加尖括号<>
,尖括号里面放数据类型,表明这个集合只能保持特定类型的对象。
泛型类和接口
public interface Map<K,V>
使用语法
List<String> strList = new ArrayList<String>();
泛型的使用不仅仅是在集合类中,我们可以为任何类声明泛型。
当创建带泛型声明的自定义类,为该类定义构造器时,构造器名还是原来的类名,不带泛型声明。例如:使用
Apple<T>
类定义构造器,构造器名还是Apple
。
继承带泛型的父类
-
错误示例:
-
-
方法1:传入String类型
方法2:把当成Object处理
方法3:与SubTestMap的<T>
类型相同
不存在泛型类
不管泛型的参数类型如何,他们运行时总是相同的类。例如,
ArrayList<String>
和ArrayList<Integer>
运行时是同一个类,也就是说
ArrayList<String> strList = new ArrayList<String>();
ArrayList<Integer> intList = new ArrayList<Integer>();
// 输出结果为true
System.out.println(strList.getClass() == intList.getClass());
类型通配符
类型通配符是一个问号?
,意思是位置类型元素。比如List<?>
,意思是未知类型的List集合元素。但是可以肯定的是一定总是Object。
public void test(List<?> l){
}
泛型方法
泛型方法可以在普通类中定义,也可以在泛型类中定义。
泛型方法定义如下:
public static <T> T getM(T a){
return a;
}
泛型变量的限定
如果我们使用泛型T,这意味着这可以是任意一个类的类型,但是实际上,我们想要的是这个类型T是一个实现Comparable接口的类,这时候我们就可以加限定了。
-
限定语法:
-
<T extends 接口/类>
例如:
public <T extends Comparable> T min(T[] a){
...
}
-
为什么使用关键字
extends而不是使用
implements?
- 使用 extends关键字就是因为更接近子类的概念。 一个变量通配符可以有多个限定
-
T extends 类/接口 & 类/接口
例如:
T extends Comparable & Serializable
泛型擦除
JVM里没有泛型类型对象——所有对象都属于普通类。
无论何时定义一个泛型变量,都会自动提供一个相应的原始类型。原始类型名字就是删去类型参数之后的泛型类名。擦除类型变量,并替换成限定类型(无限定的变量使用Object)。
例如
public class TestGenericity <T extends Comparable & Serializable> implements Serializable {
private T a;
public TestGenericity(T a) {
this.a = a;
}
}
上面的TestGenericity的原始类型是
public class TestGenericity implements Serializable {
private Comparable a;
public TestGenericity(Comparable a) {
this.a = a;
}
}