码迷,mamicode.com
首页 > 其他好文 > 详细

泛型(二)

时间:2015-08-01 21:56:33      阅读:87      评论:0      收藏:0      [点我收藏+]

标签:

1.泛型擦除

  虚拟机没有泛型类型对象——所有对象都属于普通类,所以无论何时定义一个泛型类型,都自动提供一个相应的原始类型,原始类型的名字就是删除类型参数后的泛型类型名。类型变量擦除有三种情况:

1.如果泛型类型的类型变量没有限定(<T>) ,那么我们就用Object作为原始类型;

例如:上一节我们使用Pair<T>的原始类型如下所示:

package generic;
/**
 * 泛型类
 * @author 堕落梦醒
 *
 * @param <Object>
 */
public class Pair {
    private Object first;
    private Object second;
    public Object getFirst() {
        return first;
    }
    public void setFirst(Object first) {
        this.first = first;
    }
    public Object getSecond() {
        return second;
    }
    public void setSecond(Object second) {
        this.second = second;
    }
    
    public Pair(Object first, Object second) {
        this.first = first;
        this.second = second;
    }
    public Pair() {
        
    }
}

2.如果有限定(<T extends XClass>),我们就XClass作为原始类型;

例如:

public class Interval<T extends Comparable> {
    private T lower;
    private T upper;
}

这个类的原始类型如下所示:

public class Interval {
    private Comparable lower;
    private Comparable upper;
}

3. 如果有多个限定(<T extends XClass1&XClass2>),我们就用第一个边界的类型变量XClass1类作为原始类型;

对于情况3,为了提供效率,我们应该讲标签接口(即没有方法的接口)放在列表的末尾。

2.翻译泛型表达式

  当程序调用泛型方法时,如果擦除返回类型,编译器插入强制类型转换。例如,下面这个语句序列

Pair<Employee> pair = new Pair<Employee>();
Employee emp = pair.getFirst();

擦除getFirst的返回类型后将返回Object类型。编译器自动插入Employee的强制类型转换。也就是说,编译器把这个方法调用翻译为两条虚拟机指令:

1)对原始方法pair.getFirst()调用

2)  将返回的Object类型强制转换为Employee类型

3.翻译泛型方法(泛型在子类继承中的问题)

package generic;

import java.util.Date;

public class DateInterval extends Pair<Date>{
    
    public void setSecond(Date second) {
        super.setSecond(second);
    }
}

DateInterval 这个类想重写父类的setSecond方法,但是对于编译器并没有重写。因为pair类泛型擦除后setSecond(T second)变成了setSecond(Object second).但是DateInterval 类泛型擦除后setSecond方法还是setSecond(Date second)。两个方法的参数类型不一样,明显没有达到重写的要求,是两个不同的方法。这样就不能实现多态性了。

那么java编译器是如何解决这个问题的呢?编译器会在DateInterval类中生成一个桥方法。重写setSecond(Object second)方法,然后再方法里面调用setSecond(Date second)。

public void setSecond(Object second){
     setSecond((Date)second);          
}

这样在多态调用时,调用的就是这个方法,达到了我们所期待的效果。

但桥方法有时也会带来问题,假设DateInterval类中也重写了getSecond方法:那么在泛型擦除后,就会有两个getSecond方法:

Date getSecond();  //在DateInteInterval中定义的

Object getSecond(); //编译器定义的桥方法

不能这样编写java代码,它们的方法名相同并且参数也相同。但是,在虚拟机中,用参数类型和返回类型确定一个方法,因此,编译器可能产生两个仅返回类型不同的方法字节码,虚拟机能够正确地处理这一情况。

4.java泛型转换的总结:

1.虚拟机中没有泛型,只有普通的类和方法。

2.所有的类型参数都用他们的限定类型替换。

3.桥方法被合成来保持多态。

4.为保持类型安全性,必要时插入强制类型转换。

泛型(二)

标签:

原文地址:http://www.cnblogs.com/duoluomengxing/p/4694648.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!