泛型编程-类型擦除(Type Erasure) Java为例子
2022/7/23 1:25:17
本文主要是介绍泛型编程-类型擦除(Type Erasure) Java为例子,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
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)
这篇关于泛型编程-类型擦除(Type Erasure) Java为例子的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-27数据结构与算法面试题详解及练习
- 2024-12-27网络请求面试题详解与实战
- 2024-12-27数据结构和算法面试真题详解与实战教程
- 2024-12-27网络请求面试真题解析与实战教程
- 2024-12-27数据结构和算法大厂面试真题详解与实战指南
- 2024-12-27TS大厂面试真题解析与应对策略
- 2024-12-27TS大厂面试真题详解与解析
- 2024-12-27网站安全入门:如何识别和修复漏洞
- 2024-12-27SQL注入基础教程
- 2024-12-27初学者指南:理解和修复跨域漏洞