类型擦除

学过C++模板的,在使用Java泛型的时候,会感觉到有点不疑问,例如:(1)无法定义一个泛型数组、无法调用泛型参数对象中对应的方法(当然,通过extends关键字是可以做到,只是比较麻烦);(2)ArrayList<Integer>和ArrayList<String>在运行时的类型是相同的。Java中的泛型有这些问题,是它的实现机制决定的,即“类型擦除”。

  1. 类型擦除的定义:编译通过后,准备进入JVM运行时,就不再有类型参数的概念,换句话说:每定义一个泛型类型,JVM会自动提供一个对应的原生类;
public class Holder4<T> {

private T a;
private T b;
private T c; public Holder4(T a, T b, T c) {
this.a = a;
this.b = b;
this.c = c;
} public T getA() {
return a;
} public T getB() {
return b;
} public T getC() {
return c;
} public void setA(T a) {
this.a = a;
} public void setB(T b) {
this.b = b;
} public void setC(T c) {
this.c = c;
} public static void main(String[] args) {
Holder4<Automobile> holder4 = new Holder4<>(new Automobile(),new Automobile(), new Automobile()); Automobile a = holder4.getA(); //编译器帮忙转型,不需要显式转型
Automobile b = holder4.getB();
Automobile c = holder4.getC();
}
}

在Java中,每定义一个泛型类型,就会自动提供一个对应的原始类型,例如:

public class Holder4Raw {

       private Object a;
private Object b;
private Object c; public Holder4Raw(Object a, Object b, Object c) {
this.a = a;
this.b = b;
this.c = c;
} public Object getA() {
return a;
} public Object getB() {
return b;
} public Object getC() {
return c;
} public void setA(Object a) {
this.a = a;
} public void setB(Object b) {
this.b = b;
} public void setC(Object c) {
this.c = c;
} public static void main(String[] args) {
Holder4Raw holder4Raw = new Holder4Raw(new Automobile(),new Automobile(), new Automobile()); Automobile a = (Automobile) holder4Raw.getA(); //显示的转型
Automobile b = (Automobile) holder4Raw.getB();
Automobile c = (Automobile) holder4Raw.getC();
}
}
  1. 为什么选择这种实现机制?
  • 在Java诞生10年后,才想实现类似于C++模板的概念,即泛型;
  • Java的类库是Java生态中非常宝贵的财富,必须保证向后兼容(即现有的代码和类文件依旧合法)和迁移兼容(泛化的代码和非泛化的代码可互相调用)基于上面这两个背景和考虑,Java设计者采取了“类型擦除”这种折中的实现方式。
  1. Java泛型依赖编译器实现,只存在于编译期,JVM中没有泛型的概念;那么,编译器做了什么工作呢?(1)set方法是编译期检查;(2)get方法的返回值进行转型,编译器插入了一个checkcast语句。

我们通过字节码进行观察,可以看出:(1)Holder4和Holder4Raw两个类的字节码完全相同;(2)在main函数的33、41和49行就是编译器插入的checkcast语句;

public class org.java.learn.generics.Holder4<T> {
public org.java.learn.generics.Holder4(T, T, T);
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: putfield #2 // Field a:Ljava/lang/Object;
9: aload_0
10: aload_2
11: putfield #3 // Field b:Ljava/lang/Object;
14: aload_0
15: aload_3
16: putfield #4 // Field c:Ljava/lang/Object;
19: return public T getA();
Code:
0: aload_0
1: getfield #2 // Field a:Ljava/lang/Object;
4: areturn public T getB();
Code:
0: aload_0
1: getfield #3 // Field b:Ljava/lang/Object;
4: areturn public T getC();
Code:
0: aload_0
1: getfield #4 // Field c:Ljava/lang/Object;
4: areturn public void setA(T);
Code:
0: aload_0
1: aload_1
2: putfield #2 // Field a:Ljava/lang/Object;
5: return public void setB(T);
Code:
0: aload_0
1: aload_1
2: putfield #3 // Field b:Ljava/lang/Object;
5: return public void setC(T);
Code:
0: aload_0
1: aload_1
2: putfield #4 // Field c:Ljava/lang/Object;
5: return public static void main(java.lang.String[]);
Code:
0: new #5 // class org/java/learn/generics/Holder4
3: dup
4: new #6 // class org/java/learn/generics/Automobile
7: dup
8: invokespecial #7 // Method org/java/learn/generics/Automobile."<init>":()V
11: new #6 // class org/java/learn/generics/Automobile
14: dup
15: invokespecial #7 // Method org/java/learn/generics/Automobile."<init>":()V
18: new #6 // class org/java/learn/generics/Automobile
21: dup
22: invokespecial #7 // Method org/java/learn/generics/Automobile."<init>":()V
25: invokespecial #8 // Method "<init>":(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
28: astore_1
29: aload_1
30: invokevirtual #9 // Method getA:()Ljava/lang/Object;
33: checkcast #6 // class org/java/learn/generics/Automobile,get方法的转型
36: astore_2
37: aload_1
38: invokevirtual #10 // Method getB:()Ljava/lang/Object;
41: checkcast #6 // class org/java/learn/generics/Automobile,get方法的转型
44: astore_3
45: aload_1
46: invokevirtual #11 // Method getC:()Ljava/lang/Object;
49: checkcast #6 // class org/java/learn/generics/Automobile,get方法的转型
52: astore 4
54: return
}

参考资料

  1. 《Java编程思想》
  2. 《Effective Java》
  3. 《Java核心技术》

原文作者:duqicauc
转载地址:Java泛型之类型擦除 | Spring For All

from: https://zhuanlan.zhihu.com/p/31741402

Java泛型之类型擦除的更多相关文章

  1. Java泛型:类型擦除

    类型擦除 代码片段一 Class c1 = new ArrayList<Integer>().getClass(); Class c2 = new ArrayList<String& ...

  2. java 泛型的类型擦除和桥方法

    oracle原文地址:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html 在Java中,泛型的引入是为了在编译时提供强 ...

  3. Java泛型-类型擦除

    一.概述 Java泛型在使用过程有诸多的问题,如不存在List<String>.class, List<Integer>不能赋值给List<Number>(不可协变 ...

  4. 转:有关Java泛型的类型擦除(type erasing)

    转载自:拈花微笑 自从Java 5引入泛型之后,Java与C++对于泛型不同的实现的优劣便一直是饭后的谈资.在我之前的很多training中,当讲到Java泛型时总是会和C++的实现比较,一般得出的结 ...

  5. java 泛型的类型擦除与桥方法

    泛型类 --代码参考:java核心技术 卷1 第十版 public class Pair<T> { private T first; private T second; //构造器 pub ...

  6. JAVA 泛型之类型擦除

    ★ 泛型是 JDK 1.5 版本引进的概念,之前是没有泛型的概念的,但泛型代码能够很好地和之前版本的代码很好地兼容. CollectionTest.java ---编译成CollectionTest. ...

  7. Java泛型的类型擦除

    package com.srie.testjava; import java.util.ArrayList; import java.util.List; public class TestGener ...

  8. Java泛型类与类型擦除

    转载自:http://blog.csdn.net/lonelyroamer/article/details/7868820 一.Java泛型的实现方法:类型擦除 前面已经说了,Java的泛型是伪泛型. ...

  9. java之集合类框架的简要知识点:泛型的类型擦除

    这里想说一下在集合框架前需要理解的小知识点,也是个人的肤浅理解,不知道理解的正不正确,请大家多多指教.这里必须谈一下java的泛型,因为它们联系紧密,我们先看一下这几行代码: Class c1 = n ...

随机推荐

  1. Codeforces 601C Kleofáš and the n-thlon 概率dp

    Kleofáš and the n-thlon 我们可以用dp算出比当前这个人得分少的概率, 然后人数乘概率就好啦. dp[ i ][ j ]表示进行了 i 轮 得分为 j 的概率, 因为每个人都是独 ...

  2. ThinkPHP 获取指定日期后第N个工作日具体日期

    思路: 1.获取到查询年份内所有工作日数据数组2.获取到查询开始日期在工作日的索引3.计算需查询日期索引4.获得查询日期 /*创建日期类型记录表格*/ CREATE TABLE `tb_workday ...

  3. P1855 榨取kkksc03 二维费用背包

    Kkksc03的时间和金钱是有限的,所以他很难满足所有同学的愿望.所以他想知道在自己的能力范围内,最多可以完成多少同学的愿望? 输入输出格式 输入格式: 第一行,n M T,表示一共有n(n<= ...

  4. 详解VirtualBox虚拟机网络环境解析和搭建-NAT、桥接、Host-Only、Internal、端口映射

    本文以VirtualBox为例 如果出现主机无法ping通虚拟机的情况,请首先确认虚拟机防火墙已关闭. 一.NAT模式 特点: 1.如果主机可以上网,虚拟机可以上网 2.虚拟机之间不能ping通 3. ...

  5. Python3 k-邻近算法(KNN)

    # -*- coding: utf-8 -*- """ Created on Fri Dec 29 13:13:44 2017 @author: markli " ...

  6. Xamarin iOS教程之添加和定制视图

    Xamarin iOS教程之添加和定制视图 Xamarin iOS用户界面——视图 在iPhone或者iPad中,用户看到的摸到的都是视图.视图是用户界面的重要组成元素.例如,想要让用户实现文本输入时 ...

  7. Luogu1445 [Violet]樱花 ---- 数论优化

    Luogu1445 [Violet]樱花 一句话题意:(本来就是一句话的) 求方程 $\frac{1}{X} + \frac{1}{Y} = \frac{1}{N!}$ 的正整数解的组数,其中$N \ ...

  8. BZOJ.3052.[WC2013]糖果公园(树上莫队 带修改莫队)

    题目链接 BZOJ 当然哪都能交(都比在BZOJ交好),比如UOJ #58 //67376kb 27280ms //树上莫队+带修改莫队 模板题 #include <cmath> #inc ...

  9. Codeforces Round #312 (Div. 2) E. A Simple Task 线段树

    E. A Simple Task 题目连接: http://www.codeforces.com/contest/558/problem/E Description This task is very ...

  10. SLAM(一)----学习资料整理

    转自:http://www.cnblogs.com/wenhust/ 书籍: 1.必读经典 Thrun S, Burgard W, Fox D. <Probabilistic robotics& ...