Java泛型
About 4 min
Java泛型
泛型,即“参数化类型”。顾名思义,就是将类型由原来的具体的类型'参数化',此时类型也定义成参数形式,然后在使用/调用时传入具体的类型。事先不确定类型, 先写一个东西代指, 在使用的时候具体指定
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许开发者在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。在使用/调用时传入具体的类型(类型实参)。
Java采用 类型擦除(Type erasure generics) 的方式实现泛型,即这个泛型只存在源码中。
java中的泛型仅仅存在于编译之前, 经过编译之后全部泛型变成Object, 使用泛型变成类型强转
1. 注意事项
Java开发手册推荐使用:
// 泛型的写法: 一般常用T E K V (语法上可以使用别的字符都可以, 但是习惯上用这些)
// T : type
// E : element
// K : key
// V : value
class User <T> {}
// 我们可以在泛型定义的时候定义多个泛型(语法完全允许), 但是建议不要超过两个
class User <T, E, X> {
E name;
T age;
public User(E name, T age) {
this.name = name;
this.age = age;
}
}
泛型使用的写法:
User<Integer> zs1 = new User<Integer>("zs", 18); // 在引用上 和 new 类型上都指定类型: jdk1.5时候的写法
User<Integer> zs2 = new User<>("zs", 18); // 只写引用, 后面省略: jdk1.7时候做的写法优化
// 如果某个地方需要传泛型, 但是我们使用的时候没有指定具体的泛型类型, 这个泛型在这次使用中默认表现为Object
User zs = new User("zs", 18);
Object age = zs.age;
泛型不允许使用基本类型:
// 泛型的使用不允许使用基本类型
// 报错: User<int> zs3 = new User<>("zs", 18);
泛型的好处:
a. 提高了程序的安全性
b. 将运行期遇到的问题转移到了编译期
c. 省去了类型强转的麻烦
2. 泛型的使用
泛型类
// 泛型类:(在实例化泛型类时,需要指明泛型类中的类型参数,并赋予泛型类属性相应类型的值)
public class ClassName<dataType1,dataType2,…>{
private dataType1 propertyName1;
private dataType2 propertyName2;
}
// 定义一个泛型类:
public class ClassName<T>{
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
// 注意1: 定义一个泛型类, 这个泛型作用域范围, 仅在类名之后和类体上
泛型接口
// 泛型接口
public interface IntercaceName<T>{
T getData();
}
// 实现接口时,可以选择指定泛型类型,也可以选择不指定
// 指定类型 如下:
public class Interface1 implements IntercaceName<String> {
private String text;
@Override
public String getData() {
return text;
}
}
// 不指定类型:
public class Interface1<T> implements IntercaceName<T> {
private T data;
@Override
public T getData() {
return data;
}
}
泛型方法
// 泛型方法,例如:
public static <T> List find(Class<T> cs,int userId){
// 使用了泛型的方法不一定是泛型方法, 定义了泛型的方法才是泛型方法
}
- 是否拥有泛型方法,与其所在的类是不是泛型没有关系
- 如果 static 方法需要使用泛型能力,就必须使其成为泛型方法
3. 泛型通配
泛型是不允许类似数组一样协变的,但是有的时候, 我们又希望它能像数组一样, 产生类似协变的效果
泛型通配: 这个泛型通配就是为了模拟数组的协变, 又避免了数组协变的坏处(类型问题)
?
:任意类型,如果没有明确,那么就是Object以及任意的Java类了表示不确定的 java 类型,通常用于泛型方法的调用代码和形参,不能用于定义类和泛型方法
? extends E
(向下限定,E及其子类)上界通配符
< ? extends E>
:限制泛型可用类型, 表示参数化的类型可能是所指定的类型,或者是此类型的子类。- 如果传入的类型不是 E 或者 E 的子类,编译不成功
- 泛型中可以使用 E 的方法,否则需要强转成 E 才能使用
// 当没有使用 extends 关键字限制泛型类型时,其实是默认使用 Object 类作为泛型类型/ public class ClassName<T> {} // 等同于: public class ClassName<T extends Object> {}
? super E
(向上限定,E及其父类)下界通配符
< ? super E>
:表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至 Object