专栏名称: OSC开源社区
OSChina 开源中国 官方微信账号
目录
相关文章推荐
极客之家  ·  视频一键转图文,这款开源的 AI ... ·  23 小时前  
程序员小灰  ·  我的第一个副业是什么? ·  2 天前  
阿里技术  ·  Cursor入门:MCP开发调用和项目实战 ·  2 天前  
51好读  ›  专栏  ›  OSC开源社区

聊聊 Java 泛型的实现原理和一些高级特性

OSC开源社区  · 公众号  · 程序员  · 2017-03-07 08:21

正文

请到「今天看啥」查看全文



类型擦除的基本过程也比较简单,首先是找到用来替换类型参数的具体类。这个具体类一般是Object。如果指定了类型参数的上界的话,则使用这个上界。把代码中的类型参数都替换成具体的类。同时去掉出现的类型声明,即去掉<>的内容。比如T get()方法声明就变成了Object get();List 就变成了List。



泛型的实现原理


因为种种原因,Java不能实现真正的泛型,只能使用类型擦除来实现伪泛型,这样虽然不会有类型膨胀(C++模板令人困扰的难题)的问题,但是也引起了许多新的问题。所以,Sun对这些问题作出了许多限制,避免我们犯各种错误。


保证类型安全

首先第一个是泛型所宣称的类型安全,既然类型擦除了,如何保证我们只能使用泛型变量限定的类型呢?java编译器是通过先检查代码中泛型的类型,然后再进行类型擦除,在进行编译的。那类型检查是针对谁的呢,让我们先看一个例子。

ArrayList arrayList1=new ArrayList(); // 正确,只能放入 String


ArrayList arrayList2=new ArrayList (); // 可以放入任意Object


这样是没有错误的,不过会有个编译时警告。不过在第一种情况,可以实现与 完全使用泛型参数一样的效果,第二种则完全没效果。因为,本来类型检查就是编译时完成的。new ArrayList()只是在内存中开辟一个存储空间,可以存储任何的类型对象。而真正涉及类型检查的是它的引用,因为我们是使用它引用arrayList1 来调用它的方法,比如说调用add()方法。所以arrayList1引用能完成泛型类型的检查。 而引用arrayList2没有使用泛型,所以不行。


类型检查就是针对引用的,谁是一个引用,用这个引用调用泛型方法,就会对这个引用调用的方法进行类型检测,而无关它真正引用的对象。


实现自动类型转换

因为类型擦除的问题,所以所有的泛型类型变量最后都会被替换为原始类型。这样就引起了一个问题,既然都被替换为原始类型,那么为什么我们在获取的时候,不需要进行强制类型转换呢?

public class Test {

public static void main(String[] args) {

ArrayList list=new ArrayList ();

list.add(new Date());

Date myDate=list.get(0);

}

}


编译器生成的class文件中会在你调用泛型方法完成之后返回调用点之前加上类型转换的操作,比如上文的get函数,就是在get方法完成后,jump回原本的赋值操作的指令位置之前加入了强制转换,转换的类型由编译器推导。



泛型中的继承关系


先看一个例子:

class DateInter extends A {

@Override

public void setValue(Date value) {

super.setValue(value);

}

@Override

public Date getValue() {

return super.getValue();

}

}


先来分析setValue方法,父类的类型是Object,而子类的类型是Date,参数类型不一样,这如果实在普通的继承关系中,根本就不会是重写,而是重载。


public void setValue(java.util.Date);  //我们重写的setValue方法







请到「今天看啥」查看全文