Java泛型 类型擦除在继承中引入的问题及编译器的解决方法

来源:互联网 发布:淘宝买官换机哪家靠谱 编辑:程序博客网 时间:2024/06/18 13:46

举例来说明类型擦除在继承中引入的问题以及编译器是如何解决的。

有一个Pair类:

package generic;/** * @version 1.00 2004-05-10 * @author Cay Horstmann */public class Pair<T> {   private T first;   private T second;   public Pair() { first = null; second = null; }   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类类型擦除后变成这样:

package generic;/** * pair<T>类型擦出后的版本,即pair<T>得原始类型; * 擦除规则是,删除类名后面的类型变量,并将类中用到 * 类型变量的地方替换为类型变量的限定类型( * 如果没有限定类型就用Object) * @author yuncong * */public class Pair {   private Object first;   private Object second;   public Pair() { first = null; second = null; }   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; }}

DateInterval继承自Pair<Date>,它表示一个时间区间,源码如下:

package generic;import java.util.Date;public class DateInterval extends Pair<Date>{public void setSecond(Date second) {if (second.compareTo(getFirst()) >= 0) {super.setSecond(second);}}}

DateInterval类型擦除后的样子如下:

package generic;import java.util.Date;public class DateInterval extends Pair{public void setSecond(Date second) {if (second.compareTo(getFirst()) >= 0) {super.setSecond(second);}}}

下面是一个测试类:

package generic;import java.util.Date;public class Test7 {public static void main(String[] args) {// TODO Auto-generated method stub// date2大于date1Date date1 = new Date();try {Thread.sleep(3000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}Date date2 = new Date();DateInterval dateInterval = new DateInterval();Pair<Date> datePair = dateInterval;datePair.setFirst(date1);datePair.setSecond(date2);System.out.println(datePair.getFirst());System.out.println(datePair.getSecond());}}

运行结果如下:

Tue Jun 09 10:25:51 CST 2015
Tue Jun 09 10:25:54 CST 2015

改动一下测试类,把first设置为date2,把second设置为date1:

package generic;import java.util.Date;public class Test7 {public static void main(String[] args) {// TODO Auto-generated method stub// date2大于date1Date date1 = new Date();try {Thread.sleep(3000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}Date date2 = new Date();DateInterval dateInterval = new DateInterval();Pair<Date> datePair = dateInterval;datePair.setFirst(date2);datePair.setSecond(date1);System.out.println(datePair.getFirst());System.out.println(datePair.getSecond());}}

运行结果如下:
Tue Jun 09 10:27:15 CST 2015
null

因为date1小于getFirst()的返回值date2,所以second并没有成功赋值为date1。可见,代码正常运行,

datePair.setSecond(date1);

执行的是DateInterval的setSecond(Date second)方法。

(问题1)

但这和我理解的不太一样。因为类型擦除后,Pair中的setSecond方法如下:

public void setSecond(Object newValue) { second = newValue; }
DateIntervalsetSecond方法如下:

public void setSecond(Date second) {if (second.compareTo(getFirst()) >= 0) {super.setSecond(second);}<span style="font-size:24px;">}</span>
按照动态绑定的规则,

datePair.setSecond(date1);

执行的应该是Pari的setSecond(Object newValue)方法,因为这个方法并没有在DateInterval被重写。

(问题1解决)

原来,编译器在DateInterval中添加了这样一个桥方法:

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

这样,就可以理解为什么上面的代码能够正常执行了。

(问题2)

这里又出现了另一个问题,如果在DateInterval中也重写了getSecond方法:

public Date getSecond() {return (Date) super.getSecond().clone();}

为了让DateIntervalgetSecond方法与Pair中的getSecond方法一致,编译器同样会在DateInterval中添加了这样一个桥方法:

public Object getSecond() {return getSecond();}

这样DateInterval就有两个方法签名一样的getSecond方法,这是不符合Java编码规则的。

(问题2解决)

原来虚拟机通过方法签名和返回类型确定一个方法,因此,编译器可以产生方法签名相同但返回类型不同的方法字节码。这是《Java核心技术 卷1》中给出的解答。

(关于问题2的解决,我有疑问)

Pair和DateInterval的getSecond方法有相同的方法签名,它俩的动态绑定执行能够顺序进行,为什么还要添加一个桥方法呢?(Java泛型类继承时,子类的类型变量要么和父类一样,要么是父类的子类,也就是说DateInterval的getSecond方法的返回类型要么是Object要么是Object的子类型,它们符合“具有协变的返回类型”)。希望知道答案的朋友能给在评论中给出答案。

1 0
原创粉丝点击