1.为什么要有泛型
适用于多种类型执行相同代码;在编译期能够检查类型安全,减少运行时的类型转换异常。
2. 泛型类和泛型接口的定义
泛型类的定义:
public class NormalGeneric<T> {
private T data;
public NormalGeneric() {
}
public NormalGeneric(T data) {
this.data = data;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static void main(String[] args){
NormalGeneric<String> normalGeneric = new NormalGeneric<>();
normalGeneric.setData("Food");
System.out.println(normalGeneric.getData());
}
}
泛型接口的定义:
public interface Generot<T> {
public T next();
}
泛型方法的定义:
public class GenericMethod {
//修饰符 返回符
public <T> T genericMethod(T...a){
return a[a.length/2];
}
public static void main(String[] args){
GenericMethod genericMethod = new GenericMethod();
System.out.println(genericMethod.genericMethod("apple", "pear", "banana"));
}
}
3. 泛型中的标记符含义
| 标记符 | 含义 |
|---|---|
| E | Element (在集合中使用,因为集合中存放的是元素) |
| T | Type(Java 类) |
| K | Key(键) |
| V | Value(值) |
| N | Number(数值类型) |
| ? | 不确定的java类型 |
4. 泛型中的约束和局限性
- 不能实例化泛型
public class GenericTest<T> {
public GenericTest() {
T t = new T();
}
}
上述代码在编译时就会报错,因为无论是Java还是kotlin在编译期间都无法确定泛型参数的类型,所以为了防止类型问题,编译器不支持直接对泛型实例化。
- 无法获取泛型Class类型且不能用instanceOf关键字去判定泛型参数的类型
public class Restrict<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static void main(String[] args){
Restrict restrict = new Restrict();
Restrict<String> r1 = new Restrict<>();
Restrict<Integer> r2 = new Restrict<>();
System.out.println(r1.getClass() == r2.getClass());
}
}
上述代码返回的结果一定是true,因为泛型被擦除后,无论是Restrict<String>还是Restrict<Integer>获取的都是同一个Restrict class而不是Restrict<T> class。
编译器是不支持用instanceOf去判断泛型类型的。
5. 限定类型变量
当我们进行代码逻辑编写时,需要调用某个类的方法,我们就可以对类型变量进行多重限定(类要写在最前面)
6. 通配符
| 通配符(Java/Kotlin) | 含义 | 局限性 |
|---|---|---|
| ? / * | 无界通配符,表示未知的数据类型 | 不可对类型变量进行多重限定, 而T可以用&进行多重限定 |
| extends/out | 上界通配符,包括它的子类和本身 | 生产者,向外提供数据(无法添加元素,只能获取元素) |
| super/in | 下界通配符,包括它的本身和超类 | 消费者,可以添加元素,但不能按照泛型类型读取元素 |