1. 引言
当我们使用 List 创建集合的时候,IDEA 会提示我们为这个集合写入泛型。泛型可以理解为这个集合的标签,标明了这个集合可以存储什么类型的数据。当然,我们也可以不写入泛型,这样创建出来的集合可以存储任意类型的数据,但都被当做 Object 类型处理。这样当我们取数据的时候,只能得到 Object 类型的数据,而不是我们存入时的数据类型。我们需要强制类型转换,才能得到我们想要的类型,这样处理不仅麻烦而且还会有安全性问题。
2. 什么是泛型
Java 泛型是 JDK5 引入的一个新特性,泛型提供了编译时类型安全检测机制,使得程序员能在编译期检测到非法的数据类型。
泛型的格式:<数据类型>
泛型的本质是参数化类型,就是给类型指定一个参数,使用的时候在指定参数具体的值。比如
// 创建一个String类型的list
List<String> list = new ArrayList<>();
// 创建一个Integer类型的list
List<Integer> list = new ArrayList<>();
泛型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。需要注意的是:
- 泛型的数据类型只能填写引用数据类型,不可以使用基本数据类型;
- 指定泛型的具体类型之后,可以传入该类类型或其子类类型的对象。
3. 为什么使用泛型
3.1 安全性
引言中我们提到,如果创建集合的时候不指定泛型,取数据的时候得到的是 Object 类型的数据,强制类型转换可能会报错。比如:
List list = new ArrayList();
list.add("generic");
list.add(123);
我们往一个没有写入泛型的 list 中写入了字符串和一个数字,取数据时我们想得到 String 类型的数据,需要进行强制类型转换:
for(int i = 0; i < list.size(); i++){
String s = (String)list.get(i);
}
当 get 到 123 的时候,代码会报错,因为 Integer 类型不能转换成 String 类型。
所以我们创建容器时指定泛型,就避免了上述问题。
3.2 不需要类型转换
使用 List<String> list = new ArrayList<>()
创建一个 list,只能存储 String 类型的数据,并且取出的时候就是 String 类型,不需要转换。
4. 泛型的使用
泛型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。泛型标识可以理解为类型的形参,常用的泛型标识有 T 、 E 、 K 、 V:
- T ----Type(Java类)
- E ----Element(在集合中使用,因为集合中存放的是元素)
- K ----Key(键)
- V ----Value(值)
4.1 泛型类
创建一个泛型类的语法:
public class 类名<泛型标识> {
private 泛型标识 变量名;
}
使用泛型类:
类名<具体的数据类型> 对象名 = new 类名 <具体的数据类型>();
Java1.7以后,= 后面的 <> 中的具体的数据类型可以省略不写。
类名<具体的数据类型> 对象名 = new 类名<>();
例:
创建一个泛型类:
public class GenericClass<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
使用该泛型类:
public class Test {
public static void main(String[] args) {
GenericClass<String> genericClass = new GenericClass<String>();
genericClass.setT("zk");
System.out.println(genericClass.getT());
}
}
4.1.1 泛型类的继承
- 子类也是泛型类,子类和父类的泛型要一致:
class Child<T> extends GenericClass<T> {
};
- 子类不是泛型类,父类要明确泛型的数据类型:
class Child extends GenericClass<Integer> {
};
4.2 泛型接口
定义泛型接口的语法:
interface 接口名称<泛型标识> {
泛型标识 方法名();
}
使用泛型接口:
- 实现类也是泛型类,实现类和接口的泛型类型要一致;
- 实现类不是泛型类,接口要明确数据类型。
例如:
泛型接口:
public interface GenericInterface<T> {
T getValue();
}
实现类:
public class Test01<T> implements GenericInterface<T> {
private T t;
public void setT(T t) {
this.t = t;
}
public T getValue() {
return t;
}
}
使用:
public class Test {
public static void main(String[] args) {
Test01<String> test01 = new Test01<>();
test01.setT("hello");
System.out.println(test01.getValue());
}
}
4.3 泛型方法
创建泛型方法的语法:
修饰符 <泛型标识> 返回值类型 方法名(泛型标识 形参){
方法体...
}
注:
- 只有声明了
<T>
的方法才是泛型方法,<T>
表明该方法将使用泛型类型 T,此时才可以在方法中使用泛型类型 T。
public class GenericMethod {
private <T> T print(T t){
System.out.println(t);
return t;
}
public static void main(String[] args) {
GenericMethod genericMethod = new GenericMethod();
System.out.println(genericMethod.print("hello"));
}
}