java 泛型深入

java 泛型深入

本文将由浅入深介绍java泛型机制,作者理解有限,有错误的地方欢迎指正。

java泛型基础

JDK1.5以后开始支持泛型,在引入泛型之后,原始的复杂类型可以划分为多个类型;
泛型与C++的模板机制类似,目的是实现更为抽象的解耦。更方便的创建通用的数据类型。

定义泛型

  • 在类中定义泛型
 // 此处定义了两个泛型,T和S,T为任意的数据类型,S约束此泛型必须继承自T
 public class TestClassDefine<T, S extends T>{}
  • 在方法中定义泛型
    泛型类的方法可以在普通类和泛型类的内部加以定义
  // 定义了两个泛型方法,同上面一样,S具有约束条件
  public <T, S extends T> T testGenericMethodDefine(T t, S s){}
  // 定义静态的泛型方法
  public static <T> print(T[] arr);
  • 创建泛型类
/**
 * 泛型类对象
 */
class Pair<T, S> {
    T first;
    S second;

    public Pair(T f, S s) {
        first = f;
        second = s;
    }

    @Override
    public String toString() {
        return "Pair [first=" + first + ", second=" + second + "]";
    }

}

实例化泛型对象

  • 直接使用具体的数据类型替代泛型。
Pair<String, Integer> p = new Pair<>("yangtr", 21);
System.out.println(p);
// output
// Pair [first=yangtr, second=21]
  • 继承或实现接口时,若基类存在泛型,则子类也必须实现泛型
 public class MyList<E> extends ArrayList<E> implements List<E> {...} 

对泛型对象的界限限制

类型对象可以使用界限进行限制

// 此处对对象类型进行限制
// 提供两个或者多个修饰符,使用 & 连接
public static <T extends Comparable & Cloneable> void min(T[] arr){}
使用通配符类型对泛型对象进行约束
名称语法意义
下界通配符? extends BB的任何子类型
上界通配符? super BB的任何超类型
无界统配符?任何类型
// 对实现Comparable的超类型进行限制
// Comparable接口的类型参数是数组元素类型任意的任意超类型
public static <T extends Comparable<? super T>> T min(T[] arr){}

Java擦除机制

Java 虚拟机使用原始数据类型而不是泛型进行工作
泛型的原始数据类型是通过擦除变量获得的

类型擦除指的是通过类型参数合并,将泛型类型实例关联到同一份字节码上。
编译器只为泛型类型生成一份字节码,并将其实例关联到这份字节码上。
类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。
类型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。

类型擦除的主要过程如下:

  1. 将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
  2. 移除所有的类型参数。

JVM擦除后的类

class Pair{
    Object first;
    Object second;

    public Pair(Object f, Object s) {
        first = f;
        second = s;
    }

    @Override
    public String toString() {
        return "Pair [first=" + first + ", second=" + second + "]";
    }

}

擦除机制可以方便泛型程序与旧式程序接口,但也会带来一些问题

  1. 不能实例化泛型数组 T[] t = new T[10]; 非法,必须使用Object数组进行强制转换
  2. 不能实例化泛型对象 T t = new T(); 使用Object对象代替

总结

  • 虚拟机中没有泛型,只有普通类和普通方法

  • 所有泛型类的类型参数在编译时都会被擦除

  • 创建泛型对象时请指明类型,让编译器尽早的做参数检查(Effective Java,第23条:请不要在新代码中使用原生态类型)

  • 不要忽略编译器的警告信息,那意味着潜在的ClassCastException等着你。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值