JAVA语法糖原理你知道吗
目录
- Java语法糖
- 1.基本概念
- 1.1语法糖
- 1.2解语法糖
- 2.常见糖块
- 2.1 switch 支持 String 与枚举
- 2.2泛型
- 2.3自动装箱与拆箱
- 2.4方法变长参数
- 2.5枚举
- 2.6条件编译
- 2.7 for : each循环
- 3.最后
- 3.1Java编译与反编译
- 总结
Java语法糖
几乎所有的编程语言都或多或少提供过一些语法糖来方便程序员的代码开发,这些语法糖虽然不会提供实质性的功能改进,但是它们或能提高效率,或能提升语法的严谨性,或能减少编码出错的机会。
1.基本概念
1.1语法糖
语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家 Peter.J.Landin 发明的一个术语,指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。简而言之,语法糖让程序更加简洁,有更高的可读性。
1.2解语法糖
解语法糖
前面提到过,语法糖的存在主要是方便开发人员使用。但其实,Java虚拟机并不支持这些语法糖。这些语法糖在编译阶段就会被还原成简单的基础语法结构,这个过程就是解语法糖。Java语言中,javac命令可以将后缀名为.java的源文件编译为后缀名为.class的可以运行于Java虚拟机的字节码。
如果你去看com.sun.tools.javac.main.JavaCompiler的源码,你会发现在compile()中有一个步骤就是调用desugar(),这个方法就是负责解语法糖的实现的。
~~此处需要javac的源码
2.常见糖块
2.1 switch 支持 String 与枚举
都知道,Java中的swith自身原本就支持基本类型。比如int、char等。对于int类型,直接进行数值的比较。对于char类型则是比较其ascii码。所以,对于编译器来说,switch中其实只能使用整型,任何类型的比较都要转换成整型。比如byte。short,char(ackii码是整型)以及int。
演示代码:
public static void main(String[] args) { } // @Test public void Test1(){ // Scanner scanner=new Scanner(System.in); // String next = scanner.next(); String next="小高"; switch (next){ case "小高": System.out.println("我是小高"); break; case "大高": System.out.println("我最美"); break; } }
解释:
2.2泛型
通常情况下,一个编译器处理泛型有两种方式:Code specialization和Code sharing。C++和C#是使用Code specialization的处理机制,而Java使用的是Code sharing的机制。
2.3自动装箱与拆箱
自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱。因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作为自动装箱和拆箱。
演示代码:
public static void main(String[] args) { Integer a=1;//自动装箱 int b=a;//自动拆箱 }
解析:
可以看到,自动拆箱与装箱分别封装了Integer中的intValue()与valueOf()方法。
2.4方法变长参数
可变参数(variable arguments)是在Java 1.5中引入的一个特性。它允许一个方法把任意数量的值作为参数。常见的就是printf()方法。
public static void main(String[] args) { print("高冷", "公众号:高冷小伙", "博客:高冷小伙"); } public static void print(String... strs) { for (int i = 0; i < strs.length; i++) { System.out.println(strs[i]); } }
从反编译后代码可以看出,可变参数在被使用的时候,他首先会创建一个数组,数组的长度就是调用该方法是传递的实参的个数,然后再把参数值全部放到这个数组当中,然后再把这个数组作为参数传递到被调用的方法中。
**注:**String…是java5新加入的功能,表示的是一个可变长度的参数列表。
2.5枚举
Java 枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一个年的 12 个月份,一个星期的 7 天,方向有东南西北等。Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割。例如定义一个颜色的枚举类。
演示代码:
public enum t { SPRING,SUMMER; }
反编译后的代码:
public final class T extends Enum { private T(String s, int i) { super(s, i); } public static T[] values() { T at[]; int i; T at1[]; System.arraycopy(at = ENUM$VALUES, 0, at1 = new T[i = at.length], 0, i); return at1; } public static T valueOf(String s) { return (T)Enum.valueOf(demo/T, s); } public static final T SPRING; public static final T SUMMER; private static final T ENUM$VALUES[]; static { SPRING = new T("SPRING", 0); SUMMER = new T("SUMMER", 1); ENUM$VALUES = (new T[] { SPRING, SUMMER }); } }
通过反编译后代码我们可以看到,public final class T extends Enum,说明,该类是继承了Enum类的,同时final关键字告诉我们,这个类也是不能被继承的。
当我们使用enmu来定义一个枚举类型的时候,编译器会自动帮我们创建一个final类型的类继承Enum类,所以枚举类型不能被继承。
2.6条件编译
Java语法的条件编译,是通过判断条件为常量的if语句实现的。根据if判断条件的真假,编译器直接把分支为false的代码块消除。通过该方式实现的条件编译,必须在方法体内实现,而无法在正整个Java类的结构或者类的属性上进行条件编译。
2.7 for : each循环
for:each循环比for循环的代码量要少很多,但实际上就是使用了For循环和迭代器。
演示代码:
public static void main(String[] args) { String[] strs={"高效","高冷","高超","高速"}; for(String str:strs){ System.out.println(str); } }
解析:
public static void main(String[] args) { String[] strs = new String[]{"高效", "高冷", "高超", "高速"}; String[] var2 = strs; int var3 = strs.length; for(int var4 = 0; var4 < var3; ++var4) { String str = var2[var4]; System.out.println(str); } }
3.最后
3.1Java编译与反编译
java cp D:\JVM_Study\src\SyntacticSugar\SwitchDemo.java 参数是cp,路径是.java文件的路径 javap -c D:\JVM_Study\out\production\JVM_Study\SyntacticSugar\SwitchDemo.class 参数是c 路径是的.class文件路径 3.1Java编译与反编译 ~~~java java cp D:\JVM_Study\src\SyntacticSugar\SwitchDemo.java 参数是cp,路径是.java文件的路径 javap -c D:\JVM_Study\out\production\JVM_Study\SyntacticSugar\SwitchDemo.class 参数是c 路径是的.class文件路径
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!