算命免费,东宫电视剧,青蛙王子-硬核萝卜,有趣有料的新闻热点

频道:今日头条 日期: 浏览:266

本文从 Java 编译原理视点,深化字节码及 class 文件,抽丝剥茧,了解 Java 中的语法糖原理及用法,协助咱们在学会怎样运用 算命免费,东宫电视剧,青蛙王子-硬核萝卜,风趣有料的新闻热点Java 语法糖的一同,了解这些语法糖背面的原理

语法糖

语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家 Peter.J.Landin 创造的一个术语,指在计算机言语中增加的某种语法,这种语法对言语的功用并没有影响,可是更便利程序员运用。简而言之,语法糖让程序愈加简练,有更高的可读性。

有意思的是,在编程范畴,除了语法糖,还有语法盐和语法糖精的说法,篇幅有限这儿不做扩展了。

咱们所熟知的编程言语中简直都有语法糖。作者以为,语法糖的多少是评判一个言语够不够牛逼的规范舒淇的老公是谁之一。

许多人说Java是一个"低糖言语",其实从Java 7开端Java言语层面上一向在增加各种糖,首要是在"Project Coin"项目下研制。尽管现在Java有人仍是以为现在的Java是低糖,未来还会持续向着"高糖"的方向开展。

解语法糖

前面提到过,语法糖的存在首要是便利开发人员运用。但其实,Java虚拟机并不支撑这些语法糖。这些语法糖在编译阶段就会被还原成简略的根底语法结构,这个进程便是解语法糖。

提到编译,咱们肯定都知道,Java言语中,javac指令能够将后缀名为.java的源文件编译为后缀名为.class的能够运转于Java虚拟机的字节码。

假如你去看com.sun.tools.javac.main.JavaCompiler的源码,你会发现在compile()中有一个进程便是调用desugar(),这个办法便是担任解语法糖的完成的。

Java 中简伯丞最常用的语法糖首要有泛型、变长参数、条件编译、主动拆装箱、内部类等。本文首要来剖析下这些语法糖背面的原理。一步一步剥去糖衣,看看其本质。

糖块一、 switch 支撑 String 与枚举

前面提到过,从Java 7 开端,Java言语中的语法糖在逐步丰厚,其间一个比较重要的便是Java 7中switch开端支撑String。

在开端coding之前先科普下,Java中的swith自身原本就支撑底子类型。比方int、char等。

关于int类型,直接进行数值的比较。关于char类型则是比较其ascii码。

所以,关于编译器来说,switch中其实只能运用整型,任何类型的比较都要转化成整型。比方byte。short,char(ackii码是整型)以及int。

那么接下来看下switch对String得支撑,有以下代码:

后内容如下

看到这个代码,你知道本来字符串的switch是经过equals()和hashCode()办法来完成的。还好hashCode()办法回来的是int,而不是long。

细心看下能够发现,进行switch的实践是哈希值,然后经过运用equals办法比较进行安全查看,这个查看是必要的,因为哈希或许会发作磕碰。因而它的功用是不如运用枚举进行switch或许运用纯整数常量,但这也不是很差。

糖块二、 泛型

咱们都知道,许多言语都是支撑泛型的,可是许多人不知道的是,不同的编译器关于泛型的处理办法是不同的。

通常情况下,一个编译器处理泛型有两种办法:Code specialization和Code sharing。

C++和C#是运用Code specialization的处理机制,而Java运用的是Code sh花笺记aring的机制。

Code sharing办法为每个泛型类型jbdxbl创立仅有的字节码表明,而且将该泛型类型的实例都映射到这个仅有的字节码表明上。将多种泛型类形实例映射到仅有的字节码表明是经过类型擦除(type erasue)完成的。

也便是说,关于Java虚拟机来说,他底子不知道Map map这样的语法。需求在编译阶段经过类型擦除的办法进行解算命免费,东宫电视剧,青蛙王子-硬核萝卜,风趣有料的新闻热点语法糖。

类型擦除的首要进程如下:

1.将一切的泛型参数用其最左鸿沟(最尖端的父类型)类型替换。

2.韩国道德2017移除一切的类型参数。

以下代码:

2.移除一切的类型参数。

解语法糖之后会变成:


以下代码:

类型擦除后会变成:

虚拟机中没有泛型,只要一般类和一般办法,一切泛型类的类型参数在编译时都会被擦除,泛型类并没有自己独有的Class类目标。比方并不存在List.class或是List.class,而只要List.class。糖块三、 主动装箱与拆箱

主动装箱便是Java主动将原始类型值转化成对应的目标,比方将int的变量转化成Integer目标,这个进程叫做装箱,反之将黄星澄Integer目标转化成int类型值,这个进程叫做拆箱。参阅:

因为这儿的装箱和拆箱是主动进行的非人为转化,所以就称作为主动装箱和拆箱。

原始类型byte, short, char, int, long, float, double 和 boolean 对应的封装类为Byte, Short, Character, Integer, Long, Float, Double, Boolean。

先来看个主动装箱的代码:

反编译后代码如下:

再来看个主动拆箱的代码:

反编译后代码如下:

从反编译得到内容能够看出,在装箱的时分主动调用的是Integer的v算命免费,东宫电视剧,青蛙王子-硬核萝卜,风趣有料的新闻热点alueOf(int)办法。而在拆箱的时分主动调用的是Integer的intValue办法。

所以,装箱进程是经过调用包装器的valueOf办法完成的,而拆箱进程是经过调用包装器的 xxxValue办法完成的。

糖块四 、 办法变长参数

可变参数(variable arguments)是在Java 1.5中引进的一个特性。它答应一个办法把恣意数量的值作为参数。

看下以下可变参数代码,其间print办法接纳可变参数:


反编译后代码:

从反编译后代码能够看出,可变参数在被运用的时分,他首要会创立一个数组,数组的长度便是调用该办法是传递的实参的个数,然后再把参数值悉数放到这个数组傍边,然后再把这个数组作为参数传递到被调用的办法中。糖块五 、 枚举

Java SE5供给了一种新的类型-Java的枚举类型,关键字enum能够将一组签字的车管一切人水车能洗白值的有限调集创立为一种新的类型,而这些签字的值能够作为惯例的程序组件运用,佐仓树里这是一种十分有用的功用。参阅:

要想看源码,首要得有一个类吧,那么枚举类型究竟是什么类呢?是enum吗?

答案很明显不是,enum就和class相同,仅仅一个关键字,他并不是一个类。

那么枚举是由什么类保护的呢,咱们简略的写一个枚举:

然后咱们运用反编译,看看这段代码究竟是怎样完成的,反编译后代码内容如下:

经过反编译后代码咱们能够看到,public final class T extends Enum,阐明,该类是承继了Enum类的,一同final关键字告知咱们,这个类也是不能被承继的。

当咱们运用enmu来界说91撸一个枚举类型的时分,编译器会主动帮咱们创立一个final类型的类承继Enum类,所以枚举类型不能被承继。

糖块六 、 内部类

内部类又称为嵌套类,能够把内部类理解为外部类的一个一般成员。

内部类之所以也是语法算命免费,东宫电视剧,青蛙王子-硬核萝卜,风趣有料的新闻热点糖,是因为它仅仅是一个编译时的概念。

outer.java里边界说了一个内部类inner,一旦编译成功,就会生成两个彻底不同的.class文件了,别离是outer.class和outer$inner.class。所以内部类的姓名彻底能够和它的外部类姓名相同。

以上代码编译后会生成两个class文件:OutterClass$InnerClass.class 、OutterClass.class 。

当320926咱们测验运用jad对OutterClass.class文件进行反编译的时分,指令行会打印以下内容:

他会把两个文件悉数进行反编译,然后一同生成一个OutterClass.jad文件。文件内容如下:

糖块七 、条件编译

—般情况下,程序中的每一行代码都要参与编译。但有时分出于对程序代邹友开与祖海成婚照码优化的考虑,期望只对其间一部分内容进行编译,此刻就需求在程序中加上条件,让编译器只对满意条件的代码进行编译,将不满意条件的代码放弃,这便是条件编译。

如在C或CPP中,能够经过预处理句子来完成条件编译。其实在Java中也可完成条件编译。咱们先来看一段代码:

反编译后代码如下:

首要,咱们发现,在反编译后的代码中没有System.ou姚晨和凌潇肃那段被曲解的往事t.println("Hello, ONLINE!");,这其实便是条件编译。

当if(ONLINE)为false的时分,编译器就没有对其内的代码进行编译。

所以,Java语法的条件编译,是经过判别条件为常量的if句子完成的。依据if判别条件的真假,编译器直接把分支为false的代码块消除。经过该办法完成的条件编译,有必要在办法体内完成,而无法在正整个Java类的结构或许类的特点上进行条件编译。

这与C/C++的条件编译比较,的确更有限制性。在Java言语规划之初并没有引进条件编译的功用,虽有限制,可是总比没有更强。

糖块八 、 断语

在Java中,assert关键字是从JAVA SE 1.4 引进的,为了防止和老版别的Java代码中运用了assert关键字导致过错,Java在履行的时分默许是不发动断语查看的(这个时分,一切的断句子子都将疏忽!)。

假如要敞开断语查看,则需求用开关-enableassertions或-ea来敞开。

看一段包括断语的代码:

反编译后代码如下:

很明显,反编译之后的代码要比咱们自己的算命免费,东宫电视剧,青蛙王子-硬核萝卜,风趣有料的新闻热点代码杂乱的多。所以,运用了assert这个语法糖咱们节约了许多代码。

其实断语的底层完成便是if言语,假如断语成果为true,则什么都不做,程序持续履行,假如断语成果为false,则程序抛出AssertError来打断程序的履行。

-enableassert玄月梦影ions会设置$assertionsDisabled字段的值。

糖块九 、 数值字面量

在算命免费,东宫电视剧,青蛙王子-硬核萝卜,风趣有料的新闻热点java 7中,数值字面量,不管是整数仍是浮点数,都答应在数字之间刺进恣意多个下划线。这些下划线不会对字面量的数值产生影响,意图便是便利阅览。

比方:

反编译后:

反编译后便是把_删去了。也便是说编译器并不知道在数字字面量中的_,需求在编译阶段把他去掉。

糖块十 、 for-each

增强for循环(for-each)信任咱们都不生疏,日常开发常常会用到的,他会比for循环要少写许多代码,那么这个语法糖背面是怎样完成的呢?

反编译后代码如下:

代码很简略,for-each的完成原理其实便是运用了一般的for循环和迭代器。

糖块十一 、 try-with-resource

Java里,关于文件操作IO流、数据库衔接等开支十分贵重的资源,用完之后有必要及时经过close办法将其封闭,不然资源会一向处于翻开状况,或许会导致内存走漏等问题。

封闭资源的常用办法便是在finally块里是开释,即调用close办法。比新编号如,咱们常常会写这样的代码:

从Java 7开端,jdk供给了一种更好的办法封闭资源,运用try-with-resources句子,改写一下上面的代码,效果如下:

看,这简直是一大福音啊,尽管我之前一般运用IOUtils去封闭流,并不会运用在finally中写许多代码的办法,可是这种新的语法糖看上去如同高雅许多呢。

反编译以上代码,看下他的背面原理:

其实背面的原理也很简略,那些咱们没有做的封闭资源的操作,编译器都帮咱们做了。

所以,再次印证了,语法糖的效果便是便利程序员的运用,但终究仍是要转成编译器知道的言语。

糖块十二、Lambda表达式

关于lambda表达式,有人或许会有质疑,因为网上有人说他并不是语法糖。其实我想纠正下这个说法。

Labmda表达式不是匿名内部类的语法糖,可是他也是一个语法糖。完成办法其实是依靠了几个JVM底层供给的lambda相关api。

先来看一个简略的lamb看书假文雅da表达式。遍历一个list:

为啥说他并不是内部类的语法糖呢,前面讲内部类咱们说过,内部类在编译之后会有两个class文件,可是,包括lambda表达式的类编译后只要一个文件。

反编译后代码如下:

能够看到,在forEach办法中,其实是调用了java.lang.invoke.LambdaMetafactory#metafactory办法,该办法的第四个参数implMethod指定了办法完成。能够看到这儿其实是调用了一个lambda$main$0办法进行了输出。

再来看一个略微杂乱一点的,先对List进行过滤,然后再输出:

反编译后代码如下:

两个lambda表达式别离调用了lambda$main$1和lambda$main$0两个办法。

所以,lambda表达式的完成其实是依靠了一些底层的api,在编译阶段,编译器会把lambda表达式进行解糖,转化成调用内部api的办法。

或许遇到的坑

泛型——当泛型遇算命免费,东宫电视剧,青蛙王子-硬核萝卜,风趣有料的新闻热点到重载

上面这段代码,有两个重载的函数,因为他们的参数类型不同,一个是List另一个是List,可是,这段代码是编译通不过的。因为咱们前面讲过,参数List和List编译之后都被擦除了,变成了相同的原生类型List,擦除动作导致这两个办法的特征签名变得一模相同。

泛型——当泛型遇到catch

泛型的类型参数不能用在Java反常处理的catch句子中。因为反常处理是由JVM在运转时间来进行的。因为类型信息被擦除,JVM是无法区别两个反常类型MyException和MyException

泛型——当泛型内包括静态变量

以上代码输出成果为:2!因为经过类型擦除,一切的泛型类实例都相关到同一份戒五笔怎样打字节码上,泛型类的一切静态变量是同享的。

主动装箱与拆箱——目标持平比较

输出成果:

在Java 5中,在Integer的操作上引进了一个新功用来节约内存和进步功用。整型目标经过运用相同的目标引证完成了缓存和重用。

适用于整数值区间-128 至 +127。

只适用于主动装箱。运用结构函数创立目标不适用。

增强for循环

会抛出ConcurrentModifi啪啪声响cationException反常。

Iterator是作业在一个独立的线程中,而且具有一个 mutex 锁。 Iterator被创立之后会树立一个指向本来目标的单链索引表,当本来的目标数量发作变化时,这个索引表的内容不会同步改闵国辉变,所以当索引指针往后移动的时分就找不到要迭代的目标,所以依照 fail-fast 准则 Iterator 会立刻抛出java.util.ConcurrentModificationException反常。参阅:

所以 Iterator 在作业的时分是不答应被迭代的目标被改动的。但你能够运用 Iterator 自身的办法remove()来删去目标,Iterator.remove() 办法会在删去当时迭代目标的一同维儿子小说护索引的一致性。

总结

前面介绍了12种Java中常用的语法糖。所谓语法糖便是供给给开发人员便于开发的一种语法罢了。

可是这种语法只要开发人员知道。要想被履行,需求进行解糖,即转成JVM知道的语法。

当咱们把语法糖解糖之后,你就会发现其实咱们日常运用的这些便利的语法,其实都是一些其他更简略的语法构成的。

有了这些语法糖,咱们在日常开发的时分能够大大提高功率,可是一同也要防止过渡运用。运用之前最好了解下原理,防止掉坑。