Java 泛型优点之编译时类型检查
Java 泛型优点之编译时类型检查
使用泛型代码要比非泛型代码更有优势,下面是 Java 官方教程对泛型其中一个优点的介绍:
“Stronger type checks at compile time. A Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. Fixing compile-time errors is easier than fixing runtime errors, which can be difficult to find.”
现在我有两点 疑问 :
1、 在使用泛型时能在编译时被检测出的问题,在未使用泛型时是怎样的情况?即怎样才会出现这类上文中最后一句提到的不是更容易解决的运行时错误?(以代码举例)
2、 Java 如何提供这种编译时的更强的类型检查(第一句)。
解决
在 Java 还未明确的实现泛型机制之前,是具有泛型能力的,只不过没有进行语法层次上的包装。比如以容器举例。
容器的中的元素基本类型都是 Object,而由于 Java 的设计理念,Java 中所有类默认都是继承于 Object 的,所以容器中的每一个元素都可 hold 任意对象的实例。
代码如下:
ArrayList list = new ArrayList(); list.add(new String("over")); list.add(new String("loard")); ...
示意图如下:
当我们提取容器中的某一个 Object 元素时,我们只能访问到 Object 对象作用域内的实例和方法。为了访问更加具体的对象(比如上图中的 String)的方法或者实例域,我们需要告诉编译器将 Object 引用转换为 String 类型(Object 引用只能访问 String 对象的一个子集,即定义在 Object 对象中的部分。即便我们的确有一个 String 对象)。当这种转换符合继承层级时(String 是 Object 的子类),转化即可以通过编译(只是通过编译)。
String str = (String)list.get(i);
自然地,现在我们可以通过 str 访问 String 对象的方法和实例域。但是这里其实是存在潜在的问题的。Object 引用能够 hold 任意对象,那么在这个例子的容器中,意味着我们可以将其他 Object 的子类类型的对象传递给容器的元素:
list.add(new Integer(1)); //通过编译
然后当我们再次执行类型转换时,编译时没问题(因为实际是 String(Object) ),但程序将会在运行时抛出一个异常。
String str = (String)list.get(i); //抛出 ClassCastException 异常
尽管异常机制会提醒我们程序发生了我们未预期的情况,并将这些错误反馈给我们,然而如果问题能在编译时被解决,我们更希望在编写代码时就将错误避免掉。
当 Java 引入泛型机制后,这一目标可以被实现。Java 的泛型机制主要特点便是在原来的类型转化机制上增加类型参数和类型擦除机制。
所以当我们再次使用容器时,我们将给它传递一个类型参数:
ArrayList<String> list = new ArrayList<>();
这样当我们将不是 String 类型的对象传递给容器的元素时,编译器将会提示我们类型错误。如此一来,之前的类型转换错误就被阻挡在了编译时期。
但是,Java 为了向前兼容使用普通的类型转换的代码而采用的擦除机制并不是很强大(相比 C++)。
比如对于泛型函数来说,使用擦除机制的泛型似乎并没有带来什么改观(类型安全方面)。
类型擦除的例子:
public <T extend SomeObject> f(T t) { //默认 T 继承于 Object T a = t; Sysyem.out.println(a); }
当我们对这个方法调用后,编译器将进行对类型的擦除,经编译器处理后的代码如下:
public SomeObject f(SomeObject t) { SomeObject a = t; Sysyem.out.println(a); }
由于编译器在编译时将我们传递的类型信息擦除掉(无法获得类型信息),所以一旦我们进行不合法的类型转换,编译器也不会察觉:
public <T extend Object> f(T t) { ... String str = (String)t; ... } //类型擦除后 public Object f(Object t) { ... String str = (String)t; //编译完全没问题 ... }
当我们调用该方法:
f(new Integer(1)); //在运行时将抛出一个 ClassCastException
对比 C++ 的模板,C++ 将在编译时通过传递的类型参数检测到存在非法的类型转换(C++ 元编程具有将运行时检测迁移到编译期的能力)。
所以,问题应该算是被解决了(虽然有些简陋和仓促)。
感谢阅读
转载请注明出处
参考资料:
泛型类型擦除
https://docs.oracle.com/javase/tutorial/java/generics/genTypes.html
Java 泛型类型安全
https://stackoverflow.com/questions/44841156/java-generics-type-safety
Java 中的类型转换
https://stackoverflow.com/questions/5289393/casting-variables-in-java
C++ 和 Java 中的泛型机制的不同
运行时 VS 编译时
https://stackoverflow.com/questions/846103/runtime-vs-compile-time
《Java 编程思想》第四版 通过异常处理错误 (为什么编译时解决问题要比运行时解决问题要好的原因之一)

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Java体系结构
之前一直在用Java,但对Java的体系结构并不是很了解,最近也是看书才开始关注这方面的内容,做了一些笔记,摘抄给大家共同学习。 Java体系结构包括四个独立但相关的技术: Java程序设计语言 Java class文件格式 Java应用编程接口( APl) Java虚拟机 当编写并运行一个Java程序时, 就同时用到了这四种技术。 用Java编程语言编写源代码, 把它编译成Java class文件, 然后再在Java虚拟机中运行class文件。 当编写程序时, 通过调用类(这些类实现了Java API)中的方法来访问系统资源(比如I/0)。当程序运行的时候,它通过调用class文件中实现了Java APl的方法来满足程序的Java API调用,通过下图看一下这四者之间的联系。 ava虚拟机和ava API一起组成了一个“平台",所有Java程序都在这上面编译。 Java虚拟机和Java API的组合除了被称为Java运行时系统之外, 还被称为Java平台(从版本1.2开始, 称为Java2平台)。 Java程序可以在不问的计算机上运行,这是因为Java平台自已可以用软件实现。 下面先...
- 下一篇
再谈GC3:GC调优思路与常用工具
5. GC 调优(基础篇) - GC参考手册 2017年02月14日 17:41:49 阅读数:4893 说明: Capacity: 性能,能力,系统容量; 文中翻译为”系统容量“; 意为硬件配置。 您应该已经阅读了前面的章节: 垃圾收集简介 - GC参考手册 Java中的垃圾收集 - GC参考手册 GC 算法(基础篇) - GC参考手册 GC 算法(实现篇) - GC参考手册 GC调优(Tuning Garbage Collection)和其他性能调优是同样的原理。初学者可能会被 200 多个 GC参数弄得一头雾水, 然后随便调整几个来试试结果,又或者修改几行代码来测试。其实只要参照下面的步骤,就能保证你的调优方向正确: 列出性能调优指标(State your performance goals) 执行测试(Run tests) 检查结果(Measure the results) 与目标进行对比(Compare the results with the goals) 如果达不到指标, 修改配置参数, 然后继续测试(go back to running tests) 第一步, 我们需要...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- 2048小游戏-低调大师作品
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Hadoop3单机部署,实现最简伪集群
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果