ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

泛型编程-类型擦除(Type Erasure) Java为例子

2022-07-21 23:39:24  阅读:203  来源: 互联网

标签:getSecond Erasure Java Object second 擦除 Date public first


Java中的泛型代码和C++中的模板有一个很大的不同:C++中模板的实例化会为每一种类型都产生一套不同的代码,这就是所谓的代码膨胀。
Java中并不会产生这个问题。虚拟机中并没有泛型类型对象,所有的对象都是普通类。

虚拟机中的泛型转换需要记住4条事实:
1) 定义任何一个泛型都会自动产生其原始类型(raw type)
2) 这个过程中,泛型类型会被擦除,替换为其限定类型(bounding type)
3) 必要时插入强制转换来保证类型安全
4) 使用桥接方法(bridge method)来保证正确处理多态

例如写一个返回数组中最小值的泛型函数,可以如下定义。

public static <T extends Comparable> T min(T[] a)

实际上Comparable也是一个泛型接口,所以最正确的定义方法是

public static <T extends Comparable<? super T>> T min(T[] a) 

类型擦除后,替换为限定类型Comparable,其原始类型就是

public static Comparable min(Comparable[] a)

如果没有限定类型,那么类型擦除后就替换为Object。例如一个Pair<T>类

public class Pair<T> {
    private T first;
    private T second;
 
    public Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }
 
    public T getFirst() {
        return first;
    }
 
    public T getSecond() {
        return second;
    }
 
    public void setFirst(T newValue) {
        first = newValue;
    }
 
    public void setSecond(T newValue) {
        second = newValue;
    }
}

Pair<T>类执行类型擦除后的原始类型就是

public class Pair {
    private Object first;
    private Object second;
 
    public Pair(Object first, Object second) {
        this.first = first;
        this.second = second;
    }
 
    public Object getFirst() {
        return first;
    }
 
    public Object getSecond() {
        return second;
    }
 
    public void setFirst(Object newValue) {
        first = newValue;
    }
 
    public void setSecond(Object newValue) {
        second = newValue;
    }
}

下面一段代码,
Pair<String> pair = new Pair<String>("1", "2");
String s = pair.getFirst();
类型擦除后,getFirst()返回Object。所以,编译器实际上把它转换为下面的虚拟机指令:
a) 调用原始类型的Pair.getFirst
b) 把返回的Object对象强制转换为String


类型擦除有时候会带来很复杂的情况:
例如下面写了一个新的类:

class DateInterval extends Pair<Date> {
    public DateInterval(Date first, Date second) {
        super(first, second);
    }
    
    public void setSecond(Date second) {
        if (second.compareTo(getFirst()) >= 0) {
            super.setSecond(second);
        } else {
            throw new IllegalArgumentException("Second date should be no earlier than first date.");
        }
    }
    
    public Date getSecond() {
        return (Date) super.getSecond().clone();
    }
}

类型擦除后,DateInterval中就有两个setSecond方法。
public void setSecond(Object second)
public void setSecond(Date second)
在这里,类型擦除和多态就产生了冲突。因为实际上我们是想要覆盖基类的方法。
为了解决这类问题,编译器会产生一个桥接方法
public void setSecond(Object second) {
setSecond((Date) second);
}

类型擦除后,DateInterval中有两个getSecond方法
public Date getSecond()
public Object getSecond()
在Java代码中,直接这么申明两个方法,是会导致编译错误的,因为不允许两个同名方法具有相同的参数类型。
但是,在虚拟机中,也就是编译后的代码中,参数类型加上返回类型来识别一个方法,所以这样做是允许的,因为返回类型不一样。
实际上,编译器生成这样一个桥接方法。
public Object getSecond() {
return getSecond();
}

可以使用Jad工具来反编译class文件,就能清除到看到编译器所做的工作。
例如运行jad.exe DateInterval.class,生成下面的反编译文件

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   Pair.java
 
package learning.generic;
 
import java.util.Date;
 
// Referenced classes of package learning.generic:
//            Pair
 
class DateInterval extends Pair
{
 
    public DateInterval(Date first, Date second)
    {
        super(first, second);
    }
 
    public void setSecond(Date second)
    {
        if(second.compareTo((Date)getFirst()) >= 0)
            super.setSecond(second);
        else
            throw new IllegalArgumentException("Second date should be no earlier than first date.");
    }
 
    public Date getSecond()
    {
        return (Date)((Date)super.getSecond()).clone();
    }
 
    public volatile void setSecond(Object obj)
    {
        setSecond((Date)obj);
    }
 
    public volatile Object getSecond()
    {
        return getSecond();
    }
}

参考连接:

Java-泛型编程-类型擦除(Type Erasure)

 

 

标签:getSecond,Erasure,Java,Object,second,擦除,Date,public,first
来源: https://www.cnblogs.com/2018shawn/p/16504003.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有