Java的语法糖
1.前言
本文记录内容来自《深入理解Java虚拟机》的第十章早期(编译期)优化其中一节内容,其他的内容个人觉得暂时不需要过多关注,比如语法、词法分析,语义分析和字节码生成的过程等。主要关注的就是Java的一些语法糖是如何实现的。
语法糖不会提供实质性的功能改进,但是它们或能提高效率,或能提升语法的严谨性,或能减少编码出错的可能。大量使用语法糖可能会迷失其中,不得要领,下面就介绍一下Java的语法糖的实现。
2.泛型与类型擦除
JDK5新增了一个特性,就是泛型。本质是参数化类型的应用,就是所操作的数据类型被指定为一个参数,这种参数可以应用在类、接口和方法的创建中。
Java没有泛型的时候,只能通过Object是所有类型的父类和类型强制转换两个特点的配合来实现类型泛化,比如HashMap的get方法,返回的就是Object,因为map中一切皆有可能。但是这样的操作带来了一些风险,如果强转的类型错误,就会在运行期间抛出异常,我们需要在编码期间就发现这个问题。
Java的泛型是一种伪泛型,不是C#那种传统意义上的泛型。在C#中,List<int>和List<String>是两种类型,但是Java中还是List。因为Java的泛型只存在于代码中,编译后泛型就消失了,这个就是所说的类型擦除,取而代之的就是插入了强转代码。将一段含有泛型的Java程序编译后,再反编译回来,就会发现反编译的代码中泛型消失了,新增的就是强转代码。
为什么要使用类型擦除的方式实现泛型的原因不得而知,但是这个确实是个吐槽的地方。有人说性能上泛型会由于强制转型操作和运行期缺少针对类型的优化导致速度比真正的泛型慢。这个评价角度不太对,因为泛型是用于提升语义准确性的。Java的泛型会导致一些奇特的问题。
比如重载:public static void method(List<String> list)和public static void method(List<Integer> list)这两个方法存在是不会编译通过的,因为类型擦除后是特征签名一模一样的。看似重载不正确的原因找到了:重载要求方法名相同,参数不同,返回值可同可不同。这里参数、方法名一致肯定失败了。但实际上不是,因为如果改一下一个返回String类型,一个返回Integer类型,按照重载的定义,返回值可以不同,这两个方法应该还是一样的,编译不同过才对,而实际上是可以通过的。这又是为什么呢?在Java语言中方法重载实际是要求方法具有不同的特征签名,相同的方法名。特征签名是一个方法中各个参数在常量池中的字段符号引用的集合,返回值不在其中,这样也就能理解重载的要求是方法名相同,参数不同的含义了。而修改了返回值为什么通过了呢?原因在于这不是重载的范畴,在Class文件格式中,只要描述符不是完全一致的两个方法也可以共存。方法的描述符和返回值是有关系的,所以这两个方法的描述符因为返回值的区别是不同的,可以共存,但不是重载。
3.自动装箱、拆箱与遍历循环
从技术角度来说,这些语法糖在实现和思想上都不如泛型,但是这是使用最多的语法糖。
自动装箱的操作就是:Integer.valueof(i),在编译阶段替换成了这个
自动拆箱的操作就是:Integer.intValue()
集合的foreach操作是:for(its = list.iterator; its.hasNext; ;) { its.next},采取的是迭代器的方式遍历
数组的foreach操作实际上是压栈,进栈出栈操作。
这些原理都什么简单,可以自己写一个类编译后,再反编译看看结果。
自动装箱的陷阱:
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
System.out.println(c == d);
System.out.println(e == f);
System.out.println(c == (a+b));
System.out.println(c.equals(a+b));
System.out.println(g == (a+b));
System.out.println(g.equals(a+b));
}
上面的代码执行出来1.true 2.false 3.true 4.true 5.true 6.false。
解释一下上面的含义:
首先包装类的==比较不会触发自动拆箱,所以1、2的比较是引用比较。那为什么1是true,2是false?上面说了自动装箱是通过Integer.valueof实现的,Java代码对Integer进行了优化,查看源代码可以看到有个缓存,在-128~127之间的整数,获取的是同一个Integer对象,321超过了这个范围,生成的是不同的对象。
+号会触发自动拆箱,导致==一般是int类型,而不是Integer类型,最后触发c的自动拆箱,两个int类型比较,值相等就是true了。
4中的+号也会触发自动拆箱,成int类型,但由于是equals方法,又进行了自动装箱,最后判断标准就是Integer.equals的方法,其比较就是两个int类型进行比较,所以是true
5中和3的步骤类似,但是g自动才行成了long类型,long与int比较,数值的大小比较。
6和4类似,但是最终变成了Long.equals(Integer),根据Long的equals方法,传入的必须是Long类型才可,所以返回的是false。
这个例子告诉我们代码中避免这样使用自动装箱和拆箱,掌握不牢可能发生意料之外的情况。
4.条件编译
许多语言都提供了条件编译的途径,比如C、C++的预处理器指示符#ifdef来完成条件编译,他们是用于解决编译时代码的依赖关系,但在Java中没有使用预处理器,因为不需要,编译器不是一个个编译Java文件,而是将所有编译单元的语法树顶级节点输入到待处理列表后再进行编译。
Java语言也可以实现条件编译,方法就是使用条件是常量的if语句,比如if(true){} else{},这样else模块的内容就会被省略。
这种条件编译只能写在方法体内,没有办法根据条件调整整个Java类结构。
5.其他语法糖
内部类、枚举类、断言语句、对枚举和字符串(JDK7)的switch支持、try中定义和关闭资源等。这些可以自己通过javac编译后javap -verbose进行查看字节码,理解其实现原理。
Java的语法糖的更多相关文章
- 深入理解 Java try-with-resource 语法糖
背景 众所周知,所有被打开的系统资源,比如流.文件或者Socket连接等,都需要被开发者手动关闭,否则随着程序的不断运行,资源泄露将会累积成重大的生产事故. 在Java的江湖中,存在着一种名为fina ...
- Java虚拟机 - 语法糖
[深入Java虚拟机]之六:Java语法糖 语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家Peter.J.Landin发明的一个术语,指在计算机语言中添加的某种语法,这种语 ...
- Hollis原创|不了解这12个语法糖,别说你会Java
GitHub 2.5k Star 的Java工程师成神之路 ,不来了解一下吗? GitHub 2.5k Star 的Java工程师成神之路 ,真的不来了解一下吗? GitHub 2.5k Star 的 ...
- Java语法糖4:内部类
内部类 最后一个语法糖,讲讲内部类,内部类指的就是在一个类的内部再定义一个类. 内部类之所以也是语法糖,是因为它仅仅是一个编译时的概念,outer.java里面定义了一个内部类inner,一旦编译成功 ...
- Java语法糖1:可变长度参数以及foreach循环原理
语法糖 接下来几篇文章要开启一个Java语法糖系列,所以首先讲讲什么是语法糖.语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的 ...
- Java中的10颗语法糖
语法糖(Syntactic Sugar):也称糖衣语法,指在计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用.通常来说,使用语法糖能够增加程序的可读性,减少程序代码出错的 ...
- 语法糖----JAVA
语法糖 语法糖(Syntactic Sugar),也叫糖衣语法,是英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语.指的是,在计算机语言中添加某种语法,这种语法能使程序 ...
- 转:【深入Java虚拟机】之六:Java语法糖
转载请注明出处:http://blog.csdn.net/ns_code/article/details/18011009 语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家P ...
- Java 中的语法糖
百度百科对语法糖的定义 语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这 ...
随机推荐
- Curator场景应用
分布式锁功能: 在分布式场景中,我们为了保证数据的一致性,经常在程序运行的某一个点,需要进行同步操作,(java提供synchronized或者Reentrantlock实现), 使用curator基 ...
- 【Python深入】Python中继承object和不继承object的区别
python中定义class的时候,有object和没有object的不同?例如: class Solution(object): class Solution(): 这俩的区别在于—————— 在p ...
- Django HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR
使用django来获取用户访问的IP地址,如果用户是正常情况下 request.META['REMOTE_ADDR'] 可以获得用户的IP地址.但是有些网站服务器会使用ngix等代理http,或者是该 ...
- 在桌面创建robotframework Ride的快捷方式启动RIDE
安装后robotframework-ride 后,每次启动时都要在Dos命令下启动 ,下面是创建快捷方式启动操作如下: 1.进入到python的安装目录的/Scripts目录下,找到ride.py文件 ...
- Win7 64位使用IDA Pro 6.8调试64位exe程序
有点小坑,记录备忘. 首先搞个IDA Pro6.8,写本文时能找到的最高版本,试了下果然比6.6强大许多,其实6.6也没怎么用过...... 32位版本有个Local Win32 debugger,但 ...
- C#字符串操作方法签名等
class Program { /// <summary> /// C# 里Main方法不需要public,而且不允许有两个是Main(string[] args)[包括String[] ...
- [ 9.29 ]CF每日一题系列—— 765B字符串规律
Description: 遇到了ogo可以变成***如果ogo后面有go统统忽略,输出结果 Solution: 哎如果我一开始对题意的解读如上的话,就不会被整的那么麻烦了 Code: #include ...
- MFC控件的颜色设置
在绘制控件颜色时,控件会发送WM_CTLCOLOR消息给父窗口,父窗口收到消息后,映射到OnCtlColor()函数中处理. 该函数返回一个画刷用于设置子控件的背景颜色,子控件再执行自己的CtlCol ...
- Python自动化开发 - Python操作Memcached、Redis、RabbitMQ
Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载. 它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速 ...
- 9.3AspectJ
1.1 介绍 AspectJ是一个基于Java语言的AOP框架 Spring2.0以后新增了对AspectJ切点表达式支持 @AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许 ...