
正文
C++泛型 && Java泛型实现机制
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
C++泛型
C++泛型跟虚函数的运行时多态机制不同,泛型支持的静态多态,当类型信息可得的时候,利用编译期多态能够获得最大的效率和灵活性。当具体的类型信息不可得,就必须诉诸运行期多态了,即虚函数支持的动态多态。
对于C++泛型,每个实际类型都已被指明的泛型都会有独立的编码产生,也就是说
list<int>
和
list<string>
生成的是不同的代码,编译程序会在此时确保类型安全性。由于知道对象确切的类型,所以编译器进行代码生成的时候就不用运用RTTI,这使得泛型效率跟手动编码一样高。
显然这样的做法增加了代码空间,相比运行时多态,是以空间换时间。
Java泛型
当编译器对带有泛型的 Java 代码进行编译时,它会去执行类型检查和类型推断,然后生成普通的不带泛型的字节码,这种字节码可以被一般的 Java 虚拟机接收并执行,这种技术被称为擦除(erasure)。
可见,编译器可以在对源程序(带有泛型的 Java 代码)进行编译时使用泛型类型信息保证类型安全,同时在生成的字节码当中,将这些类型信息清除掉。
如在代码中定义的
List<object>
和
List<String>
等类型,在编译后都会编程List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。
擦除的原则:
1)所有参数化容器类都被擦除成非参数化的(raw type);如
List<E>、List<List<E>
>都被擦除成List;
2)所有参数化数组都被擦除成非参数化的数组;如
List<E>[]
,被擦除成
List[]
;
3)Raw type的容器类,被擦除成其自身,如List 被擦除成List;
4)原生类型(int,String还有wrapper类)都擦除成他们的自身;
5)参数类型E,被擦除成Object;
6)所有约束参数如
<? Extends E>、<X extends E>
都被擦除成E;
7)如果有多个约束,擦除成第一个,如
<T extends Object & E>
,则擦除成Object;
来看个例子:
public class Pair<T> {
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 first) { this.first = first; }
public void setSecond(T second) { this.second = second; }
private T first;
private T second;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
擦除后变为:
public class Pair {
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 first) { this.first = first; }
public void setSecond(Object second) { this.second = second; }
private Object first;
private Object second;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
public class QMI<T extends List> {
public Interval(T value) {
this.value = value;
}
private T value;
}
- 1
- 2
- 3
- 4
- 5
- 6
擦除后:
public class QMI {
public Interval(List value) {
this.value = value;
}
Private List value;
}
- 1
- 2
- 3
- 4
- 5
- 6
那么,进行类型擦除后,在调用时怎么知道其真实类型,放心吧,编译器帮我们做好了一切,以后上面的Pair为例:
原代码为:
Pair<String> pair = new Pair<>("", "");
pair.setFirst("QMI");
pair.setSecond("Kang");
String first = pair.getFirst();
String second = pair.getSecond();
- 1
- 2
- 3
- 4
- 5
反编译后为:
Pair pair = new Pair("", "");
pair.setFirst("QMI");
pair.setSecond("Kang");
String first = (String)pair.getFirst();
String second = (String)pair.getSecond();
- 1
- 2
- 3
- 4
- 5
可以看到,编译器帮我们做了自动类型转换。
对于泛型,我们可以利用Java单根继承特性实现类似效果,但是因为此时编译器并不做类型检查,这种检查是在运行时进行的,推迟了发现程序中错误的时间。
而利用泛型机制,编译器承担了全部的类型检查工作,确保类型的安全性。以
List<Object>
和
List<String>
为例来具体分析:
public void test() {
List<String> list= new ArrayList<String>();
List.add(123); //编译错误
}
- 1
- 2
- 3
- 4
这里,声明为List的集合中却被添加了一个Integer类型的对象。这显然是违反类型安全的原则的,在某个时候肯定会抛出ClassCastException。因此,编译器禁止这样的行为。编译器会尽可能的检查可能存在的类型安全问题。对于确定是违反相关原则的地方,会给出编译错误。当编译器无法判断类型的使用是否正确的时候,会给出警告信息。此种机制有利于尽早地发现并改正错误。
让我再来看一个问题:
public class QmiV<T> {
private T value;
public T getValue() {
return this.value;
}
public void setValue(T value) {
this.value = value;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
擦除后:
public class QmiV<Object> {
private Object value;
public Object getValue() {
return this.value;
}
public void setValue(Object value) {
this.value = value;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
//子类
public class QmiVD extends QmiV<Person> {
@Override
public Person getValue() {
return super.getValue();
}
@Override
public void setValue(Person value) {
super.setValue(value);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
擦除后:
public class QmiVD extends QmiV<Person> {
public QmiVD() {
}
public String getValue() {
return (Person)super.getValue();
}
public void setValue(Person value) {
super.setValue(value);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
可以看到,对于setValue方法,父类的类型是Object,而子类的类型是Person,参数类型不一样,所以这里实现的不是重写,而是重载。
实际中,是利用桥方法解决这个问题的。
桥方法就是生成一个中间层,其参数类型都是Object,也就是说,子类中真正覆盖父类两个方法的就是两个我们看不到的桥方法。桥方法的内部再去调用我们自己重写的那两个方法。
总结:
C++泛型和Java泛型非常类似,但是有着本质不同。
首先,Java 语言中的泛型不能接受基本类型作为类型参数――它只能接受引用类型。这意味着可以定义
List<Integer>
,但是不可以定义
List<int>
。
其次,在 C++ 模板中,编译器使用提供的类型参数来生成不同代码。而 Java 中的泛型,编译器仅仅对这些类型参数进行擦除和替换。类型
ArrayList<Integer>
和
ArrayList<String>
的对象共享相同的类,并且只存在一个 ArrayList 类。
参考:
https://zh.wikipedia.org/zh-cn/%E6%B3%9B%E5%9E%8B
http://www.ibm.com/developerworks/cn/java/j-jtp01255.html
http://www.infoq.com/cn/articles/cf-java-generics
C++泛型 && Java泛型实现机制的更多相关文章
-
Java泛型解析(03):虚拟机运行泛型代码
Java泛型解析(03):虚拟机运行泛型代码 Java虚拟机是不存在泛型类型对象的,全部的对象都属于普通类,甚至在泛型实现的早起版本号中,可以将使用泛型的程序编译为在1.0虚拟机上可以执行的 ...
-
java泛型使用教程
参考: java 泛型 Java泛型中E.T.K.V等的含义 一.Java泛型中E.T.K.V等的含义 E - Element (在集合中使用,因为集合中存放的是元素) T - Type(Jav ...
-
Java-Runoob-高级教程:Java 泛型
ylbtech-Java-Runoob-高级教程:Java 泛型 1.返回顶部 1. Java 泛型 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检 ...
-
Java泛型解析(04):约束和局限性
Java泛型解析(04):约束和局限性 前两节.认识和学习了泛型的限定以及通配符.刚開始学习的人可能须要一些时间去体会到泛型程序设计的优点和力量,特别是想成为库程序猿的同学就须要下 ...
-
Java泛型解析(01):认识泛型
Java泛型解析(01):认识泛型 What Java从1.0版本号到如今的8.中间Java5中发生了一个非常重要的变化,那就是泛型机制的引入.Java5引入了泛型,主要还是为了满足在199 ...
-
Java 学习(17): Java 泛型
Java 泛型 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说将 ...
-
Java 泛型(参数化类型)
Java 泛型 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所 ...
-
重读《深入理解Java虚拟机》六、Java泛型 VS C#泛型 (伪泛型 VS 真泛型)
一.泛型的本质 泛型是参数化类型的应用,操作的数据类型不限定于特定类型,可以根据实际需要设置不同的数据类型,以实现代码复用. 二.Java泛型 Java 泛型是Java1.5新增的特性,JVM并不支持 ...
-
Java泛型解析(02):通配符限定
Java泛型解析(02):通配符限定 考虑一个这种场景.计算数组中的最大元素. [code01] public class ArrayUtil { public static <T&g ...
随机推荐
-
(39.4) Spring Boot Shiro权限管理【从零开始学Spring Boot】
在读此文章之前您还可能需要先了解: (39.1) Spring Boot Shiro权限管理[从零开始学Spring Boot] http://412887952-qq-com.iteye.com/b ...
-
一个手机图表(echarts)折线图的封装
//定义一组颜色值,按顺序取出 var colorGroup = ["#6ca3c4","#76bfa3","#ea8f7a"," ...
-
[转]十五天精通WCF——第五天 你需要了解的三个小技巧
一: 服务是端点的集合 当你在开发wcf的时候,你或许已经注意到了一个service可以公布多个endpoint,确实是这样,在wcf中有一句很经典的话,叫做“服务是端点的集合",就 比如说 ...
-
mybatis原理流程
无论是用过的hibernate,mybatis,你都可以法相他们有一个共同点: 从配置文件(通常是XML配置文件中)得到 sessionfactory. 由sessionfactory 产生 ses ...
-
我要抓狂了。。又回到了几天不能A一道题的时候
poj1556我不做了.你做做把...我已经要game over了
-
shell中eval命令
原文:http://www.cnblogs.com/xdzone/archive/2011/03/15/1984971.html 语法:eval cmdLine eval会对后面的cmdLine进行两 ...
-
恳请CSDN的活动可以落实
前言:在CSDN举办的"扒一扒你遇到过最NB开发项目"有奖征文活动中有幸获得"最佳评论奖",可是时至今日.也没有收到书籍,咨询CSDN管理员的时候.居然得到&q ...
-
读书笔记-HBase in Action-第一部分 HBase fundamentals
新项目准备上HBase.HBase眼下由组里某牛负责.本着学会使用HBase的目标,先阅读下HBase in Action,一共十章组织成三部分,须要学习的内容包含HBase基本实现原理,用法,Sch ...
-
NSDate时间类/NSDateFormatter日期格式类
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { // NSDate 时间类 继承自N ...
-
jQuery事件整理回想
一.事件 1.载入DOM $(document).ready() 这个第一节里具体介绍了 2.事件绑定 jQuery定义了bind()方法作为统一的接口.用来为每个匹配元素绑定事件处理程序. 其基本的 ...
Java泛型解析(03):虚拟机运行泛型代码 Java虚拟机是不存在泛型类型对象的,全部的对象都属于普通类,甚至在泛型实现的早起版本号中,可以将使用泛型的程序编译为在1.0虚拟机上可以执行的 ...
参考: java 泛型 Java泛型中E.T.K.V等的含义 一.Java泛型中E.T.K.V等的含义 E - Element (在集合中使用,因为集合中存放的是元素) T - Type(Jav ...
ylbtech-Java-Runoob-高级教程:Java 泛型 1.返回顶部 1. Java 泛型 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检 ...
Java泛型解析(04):约束和局限性 前两节.认识和学习了泛型的限定以及通配符.刚開始学习的人可能须要一些时间去体会到泛型程序设计的优点和力量,特别是想成为库程序猿的同学就须要下 ...
Java泛型解析(01):认识泛型 What Java从1.0版本号到如今的8.中间Java5中发生了一个非常重要的变化,那就是泛型机制的引入.Java5引入了泛型,主要还是为了满足在199 ...
Java 泛型 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说将 ...
Java 泛型 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所 ...
一.泛型的本质 泛型是参数化类型的应用,操作的数据类型不限定于特定类型,可以根据实际需要设置不同的数据类型,以实现代码复用. 二.Java泛型 Java 泛型是Java1.5新增的特性,JVM并不支持 ...
Java泛型解析(02):通配符限定 考虑一个这种场景.计算数组中的最大元素. [code01] public class ArrayUtil { public static <T&g ...
-
(39.4) Spring Boot Shiro权限管理【从零开始学Spring Boot】
在读此文章之前您还可能需要先了解: (39.1) Spring Boot Shiro权限管理[从零开始学Spring Boot] http://412887952-qq-com.iteye.com/b ...
-
一个手机图表(echarts)折线图的封装
//定义一组颜色值,按顺序取出 var colorGroup = ["#6ca3c4","#76bfa3","#ea8f7a"," ...
-
[转]十五天精通WCF——第五天 你需要了解的三个小技巧
一: 服务是端点的集合 当你在开发wcf的时候,你或许已经注意到了一个service可以公布多个endpoint,确实是这样,在wcf中有一句很经典的话,叫做“服务是端点的集合",就 比如说 ...
-
mybatis原理流程
无论是用过的hibernate,mybatis,你都可以法相他们有一个共同点: 从配置文件(通常是XML配置文件中)得到 sessionfactory. 由sessionfactory 产生 ses ...
-
我要抓狂了。。又回到了几天不能A一道题的时候
poj1556我不做了.你做做把...我已经要game over了
-
shell中eval命令
原文:http://www.cnblogs.com/xdzone/archive/2011/03/15/1984971.html 语法:eval cmdLine eval会对后面的cmdLine进行两 ...
-
恳请CSDN的活动可以落实
前言:在CSDN举办的"扒一扒你遇到过最NB开发项目"有奖征文活动中有幸获得"最佳评论奖",可是时至今日.也没有收到书籍,咨询CSDN管理员的时候.居然得到&q ...
-
读书笔记-HBase in Action-第一部分 HBase fundamentals
新项目准备上HBase.HBase眼下由组里某牛负责.本着学会使用HBase的目标,先阅读下HBase in Action,一共十章组织成三部分,须要学习的内容包含HBase基本实现原理,用法,Sch ...
-
NSDate时间类/NSDateFormatter日期格式类
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { // NSDate 时间类 继承自N ...
-
jQuery事件整理回想
一.事件 1.载入DOM $(document).ready() 这个第一节里具体介绍了 2.事件绑定 jQuery定义了bind()方法作为统一的接口.用来为每个匹配元素绑定事件处理程序. 其基本的 ...







