java教程——泛型(三)

我们在前两节讲了 泛型的基本概念泛型的简单使用,这一节我们就来讲讲 泛型的实现原理。

实现原理

泛型 根据语言的不同,有着不同的实现方法。Java语言的泛型实现方式是擦拭法(Type Erasure)。所谓擦拭法是指,虚拟机对泛型其实一无所知,所有的工作都是编译器做的。

例如,我们编写了一个泛型类selfMap<T>,这是编译器看到的代码:

class selfMap<T>{
    private T Key;
    private T value;

    public selfMap(T Key, T value) {
        this.Key = Key;
        this.value = value;
    }

    public T getTey() {
        return Key;
    }

    public T getValue() {
        return value;
    }
}

而虚拟机根本不知道泛型。这是虚拟机执行的代码:

class selfMap{
    private Object Key;
    private Object value;

    public selfMap(Object  Key, Object  value) {
        this.Key = Key;
        this.value = value;
    }

    public Object  getTey() {
        return Key;
    }

    public Object  getValue() {
        return value;
    }
}

现在,大家是不是能明白 “擦拭” 的含义了,即 将 T 擦拭为 Object 。

Java使用擦拭法实现泛型,导致了:

  • 编译器把类型<T>视为Object
  • 编译器根据<T>实现安全的强制转型。

使用泛型的时候,我们编写的代码也是编译器看到的代码:

selfMap<String> one = new selfMap<>("name","易齐");
String value = one.getValue();
System.out.println("value ->" + value);

而虚拟机执行的代码并没有泛型:

selfMap one = new selfMap("name","易齐");
String value = (String)one.getValue();
System.out.println("value ->" + value);

所以,Java的泛型是由编译器在编译时实行的,编译器内部永远把所有类型T视为Object处理,但是,在需要转型的时候,编译器会根据T的类型自动为我们实行安全地强制转型。

局限

局限一:<T>不能是基本类型,例如int,因为实际类型是ObjectObject类型无法持有基本类型:

局限二:无法取得带泛型的Class。观察以下代码:

从打印结果我们可以很直观的看到:无法取得带泛型的Class。其原因就是我们上面说的,泛型 是在编译器编译的时候实现的,到虚拟机中都是selfMap<Object>,所以,现在是不是明白了为什么打印的是一样的Class实例了。

局限三:无法判断带泛型的类型: 

局限四:不能实例化T类型:

如果你偏要实例化,也不是不可以,那我们得动用实例化第二种方法了:反射

上述代码借助Class<T>参数并通过反射来实例化T类型,使用的时候,也必须传入Class<T>。例如:

selfMap<String> stringselfMap = new selfMap<>(String.class);

因为传入了Class<String>的实例,所以我们借助String.class就可以实例化String类型。

泛型继承

一个类可以继承自一个泛型类。例如:父类的类型是selfMap<String>,子类的类型是selfStringMap,可以这么继承:

class selfStringMap extends selfMap<String>{

    public selfStringMap(String key, String value) {
        super(key, value);
    }
}

使用的时候,因为子类selfStringMap并没有泛型类型,所以,正常使用即可:

selfStringMap selfStringMap = new selfStringMap("name", "易齐");

前面讲了,我们无法获取selfMap<String>T类型,即给定一个变量selfMap<String> p,无法从p中获取到String类型。

但是,在父类是泛型类型的情况下,编译器就必须把类型T(对selfStringMap来说,也就是String类型)保存到子类的class文件中,不然编译器就不知道selfStringMap只能存取String这种类型。

个人理解:因为子类又不是泛型,所以,你不能用檫试法来保存具体类型,即子类只能将具体类型存入自己的class文件中。

在继承了泛型类型的情况下,子类可以获取父类的泛型类型。例如:selfStringMap可以获取到父类的泛型类型String。获取父类的泛型类型代码比较复杂:

package test;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;

public class changeData {

    public static void main(String[] args) {
        Class<selfStringMap> selfStringMapClass = selfStringMap.class;
        Type t = selfStringMapClass.getGenericSuperclass();
        if (t instanceof ParameterizedType){
            ParameterizedType pt = (ParameterizedType) t;
            Type[] types = pt.getActualTypeArguments();
            System.out.println(Arrays.toString(types));
        }
    }
}

class selfStringMap extends selfMap<String>{

    public selfStringMap(String key, String value) {
        super(key, value);
    }
}

class selfMap<T> extends Object{
    private T Key;
    private T value;

    public selfMap(T key,T value) {
        this.Key = key;
        this.value = value;
    }

    public T getTey() {
        return Key;
    }

    public T getValue() {
        return value;
    }
}

因为Java引入了泛型,所以,只用Class来标识类型已经不够了。实际上,Java的类型系统结构如下:

                      ┌────┐
                      │Type│
                      └────┘
                         ▲
                         │
   ┌────────────┬────────┴─────────┬───────────────┐
   │            │                  │               │
┌─────┐┌─────────────────┐┌────────────────┐┌────────────┐
│Class││ParameterizedType││GenericArrayType││WildcardType│
└─────┘└─────────────────┘└────────────────┘└────────────┘

小结

Java的泛型是采用擦拭法实现的;

擦拭法决定了泛型<T>

  • 不能是基本类型,例如:int
  • 不能获取带泛型类型的Class,例如:Pair<String>.class
  • 不能判断带泛型类型的类型,例如:x instanceof Pair<String>
  • 不能实例化T类型,例如:new T()

泛型方法要防止重复定义方法,例如:public boolean equals(T obj)

子类可以获取父类的泛型类型<T>

下一节:java教程——泛型(四)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

super码王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值