Java语法糖

您所在的位置:网站首页 糖指的是什么意思啊 Java语法糖

Java语法糖

2024-07-11 06:07| 来源: 网络整理| 查看: 265

在这里插入图片描述

文章目录 解语法糖糖块一、switch支持String与枚举糖块二、泛型和类型擦除糖块三、自动装箱与拆箱糖块四 、方法变长参数糖块五 、枚举糖块六 、内部类糖块七 、条件编译糖块八 、断言糖块九 、数值字面量糖块十 、增强for循环糖块十一 、try-with-resource语句糖块十二、Lambda表达式可能遇到的坑泛型-当泛型遇到重载泛型-当泛型遇到catch泛型-当泛型内包含静态变量自动装箱与拆箱-对象相等比较增强for循环 总结

语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家 Peter.J.Landin(彼得·兰丁) 发明的一个术语,指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。语法糖就是对现有语法的一个封装。简而言之,语法糖让程序更加简洁,有更高的可读性。

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

我们所熟知的编程语言中几乎都有语法糖。很多人说Java是一个“低糖语言”,其实从Java 7开始,Java语言层面上一直在添加各种糖,主要是在“Project Coin”项目下研发。尽管现在Java有人还是认为现在的Java是低糖,未来还会持续向着“高糖”的方向发展。

解语法糖

前面提到过,语法糖的存在主要是方便开发人员使用。但是,Java虚拟机并不支持这些语法糖。这些语法糖在编译阶段就会被还原成简单的基础语法结构,这个过程就是解语法糖。

Java中的语法糖只存在于编译期,在编译器将 .java 源文件编译成 .class 字节码时,如果你去看com.sun.tools.javac.main.JavaCompiler的源码,你会发现在compile()中有一个步骤就是调用desugar(),这个方法就是负责解语法糖而实现的。

Java 中最常用的语法糖主要有switch语句支持String与枚举、泛型和类型擦除、自动装箱与拆箱、方法边长参数、枚举、内部类、条件编译、断言、数值字面量、增强for循环、try-with-resources语句、Lambda表达式等。本文主要来分析下这些语法糖背后的原理。一步一步剥去糖衣,看看其本质。

糖块一、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的支持,有以下代码:

public class SwitchDemoString { public static void main(String[] args) { String str = "world"; switch (str) { case "hello": System.out.println("hello"); break; case "world": System.out.println("world"); break; default: break; } } }

反编译后内容如下:

public class SwitchStringDemo { public static void main(String[] args) { String str; String string = str = "world"; int n = -1; switch (string.hashCode()) { case 99162322: { if (!string.equals("hello")) break; n = 0; break; } case 113318802: { if (!string.equals("world")) break; n = 1; } } switch (n) { case 0: { System.out.println("hello"); break; } case 1: { System.out.println("world"); break; } } } }

看到这个代码,你知道原来字符串的switch是通过equals()和hashCode()方法来实现的。还好hashCode()方法返回的是int,而不是long。

仔细看下可以发现,进行switch比较的实际是哈希值,然后通过使用equals方法比较进行安全检查,这个检查是必要的,因为哈希可能会发生碰撞。因此它的性能是不如使用枚举进行switch或者使用纯整数常量,但这也不是很差。

糖块二、泛型和类型擦除

我们都知道,很多语言都是支持泛型的,但是很多人不知道的是,不同的编译器对于泛型的处理方式是不同的。

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

C++和C#是使用Code specialization的处理机制,而Java使用的是Code sharing的机制。

Code sharing方式为每个泛型类型创建唯一的字节码表示,并且将该泛型类型的实例都映射到这个唯一的字节码表示上。将多种泛型类形实例映射到唯一的字节码表示是通过类型擦除(type erasue)实现的。

也就是说,对于Java虚拟机来说,他根本不认识Map map这样的语法。需要在编译阶段通过类型擦除的方式进行解语法糖。

类型擦除的主要过程如下:

将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。移除所有的类型参数。

以下代码:

Map map = new HashMap(); map.put("name", "JourWon"); map.put("wechat", "JourWon"); map.put("blog", "https://blog.csdn.net/ThinkWon");

解语法糖之后会变成:

Map map = new HashMap(); map.put("name", "JourWon"); map.put("wechat", "JourWon"); map.put("blog", "https://blog.csdn.net/ThinkWon");

以下代码:

public static A max(Collection xs) { Iterator xi = xs.iterator(); A w = xi.next(); while (xi.hasNext()) { A x = xi.next(); if (w.compareTo(x)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3