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; }DateInterval的setSecond方法如下:
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();}
为了让DateInterval中getSecond方法与Pair中的getSecond方法一致,编译器同样会在DateInterval中添加了这样一个桥方法:
public Object getSecond() {return getSecond();}
这样DateInterval中就有两个方法签名一样的getSecond方法,这是不符合Java编码规则的。
(问题2解决)
原来虚拟机通过方法签名和返回类型确定一个方法,因此,编译器可以产生方法签名相同但返回类型不同的方法字节码。这是《Java核心技术 卷1》中给出的解答。
(关于问题2的解决,我有疑问)
Pair和DateInterval中的getSecond方法有相同的方法签名,它俩的动态绑定执行能够顺序进行,为什么还要添加一个桥方法呢?(Java泛型类继承时,子类的类型变量要么和父类一样,要么是父类的子类,也就是说DateInterval中的getSecond方法的返回类型要么是Object要么是Object的子类型,它们符合“具有协变的返回类型”)。希望知道答案的朋友能给在评论中给出答案。
- Java泛型 类型擦除在继承中引入的问题及编译器的解决方法
- JAVA泛型-类型擦除太恶心,但项目中大量使用,以及类型擦除引起的问题及解决方法
- Java泛型--编译器类型擦除
- java泛型中类型擦除以及类型擦除带来的问题
- java泛型 泛型的内部原理:类型擦除以及类型擦除带来的问题
- java泛型、泛型的内部原理:类型擦除以及类型擦除带来的问题
- java泛型 泛型的内部原理:类型擦除以及类型擦除带来的问题
- java泛型 泛型的内部原理:类型擦除以及类型擦除带来的问题
- Java的类型擦除
- 详解Java泛型(三)之类型擦除的问题
- java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题
- java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题
- java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题
- java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题
- Java泛型(二)泛型的内部原理:类型擦除以及类型擦除所带来的问题
- java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题
- java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题
- java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题
- 《黑客与画家》读书笔记2-关于“不能说的话”
- Nanos-操作系统oslab1(2)---sleep和wakeup
- 天声人語 20150609
- python多线程编程
- Java Socket编程
- Java泛型 类型擦除在继承中引入的问题及编译器的解决方法
- Linux下设置export JAVA_OPTS选项进行tomcat JVM内存设置【 linux下tomcat的参数JAVA_OPTS必须设在catalina.sh中cygwin=false前】
- ios学习笔记(一)Windows7上使用VMWare搭建iPhone开发环境
- 全局静态函数的定义和实现
- Java并发编程:Callable、Future和FutureTask
- 日经春秋 20150609
- windows下mysql每天定时备份数据库几种方法
- iOS-pthread_t自定义一个简单线程
- Eclipse for Mac 常用快捷键