JVM day04 语法糖
Posted halulu.me
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM day04 语法糖相关的知识,希望对你有一定的参考价值。
目录
语法糖(编译期间的优化)
语法糖 ,其实就是指 java 编译器把 *.java 源码编译为 *.class 字节码的过程中,自动生成和转换的一些代码,主要是为了减轻程序员的负担,算是 java 编译器给我们的一个额外福利(给糖吃 )。
1、默认构造器
编译成class文件后,在没有构造器的前提下,会自动生成无参构造器,该类的无参构造器又会自动生成父类Object的无参构造器super()。
2、自动拆箱装箱
代码片段1会在编译期间被转换为片段2。
3、泛型擦除
泛型也是在 JDK 5 开始加入的特性,但 java 在编译泛型代码后会执行 泛型擦除的动作,即泛型信息在编译为字节码之后就丢失了,实际的类型都当做了 Object 类型来处理。
擦除的是字节码上的泛型信息,可以看到 LocalVariableTypeTable 仍然保留了方法参数泛型的信息。
4、泛型反射
擦除的是字节码上的泛型信息,可以看到 LocalVariableTypeTable 仍然保留了方法参数泛型的信息。
泛型信息可以在 LocalVariableTypeTable中通过反射的方法获取。
5、可变参数
可变参数 String… args 其实是一个 String[] args 。
6、foreach
1、数组的foreach的底层就是for循环
2、集合的foreach第底层就是iterator迭代器。
数组
集合
7、switch-string
从 JDK 7 开始,switch 可以作用于字符串和枚举类,这个功能其实也是语法糖
public static void choose(String str) {
byte var2 = -1;
switch(str.hashCode()) {
case 99162322:
if (str.equals("hello")) {
var2 = 0;
}
break;
case 113318802:
if (str.equals("world")) {
var2 = 1;
}
}
switch(var2) {
case 0:
System.out.println("h");
break;
case 1:
System.out.println("w");
}
}
执行了两遍 switch,第一遍是根据字符串的 hashCode 和 equals 将字符串的转换为相应byte 类型,第二遍才是利用byte 执行进行比较。
为什么第一遍时必须既比较 hashCode,又利用 equals 比较呢?
hashCode 是为了提高效率,减少比较的次数;
而 equals 是为了防止 hashCode 冲突,
例如 BM 和 C.,这两个字符串的hashCode值都是 2123 。
8、switch-enum
从 JDK 7 开始,switch 可以作用于字符串和枚举类,这个功能其实也是语法糖
定义一个合成类数组,数组的长度就是枚举的数据,通过数组的索引来定位枚举的静态的成员常量。
9、枚举
枚举数据(MALE,FEMALE)都是实例对象。
public final class Sex extends Enum{
public static final Sex MALE;
public static final Sex FEMALE;
private static final Sex $VALUES[];
static
{
MALE = new Sex("MALE", 0);
FEMALE = new Sex("FEMALE", 1);
$VALUES = (new Sex[] {
MALE, FEMALE
});
}
private Sex(String s, int i)
{
super(s, i);
}
public static Sex[] values()
{
return (Sex[])$VALUES.clone();
}
public static Sex valueOf(String name)
{
return (Sex)Enum.valueOf(Sex.class, name);
}
}
10、twr(实现AutoClassable接口)
JDK 7 开始新增了对需要关闭的资源处理的特殊语法 try-with-resources
其中资源对象需要实现 AutoCloseable 接口,例如 InputStream 、 OutputStream 、 Connection 、 Statement 、 ResultSet 等接口都实现了 AutoCloseable ,使用 try-with- resources 可以不用写 finally 语句块,编译器会帮助生成关闭资源代码。
会被转换为:(自动关流)
public class Candy9 {
public Candy9() {
}
public static void main(String[] args) {
try {
InputStream is = new FileInputStream("d:\\\\1.txt");
Throwable var2 = null;
try {
System.out.println(is);
} catch (Throwable var12) {
var2 = var12; //是代码出现的异常
throw var12;
} finally {
if (is != null) { //判断资源不为空
if (var2 != null) { //如果代码有异常
try {
is.close();
} catch (Throwable var11) { //如果close出现异常,作为被压制异常添加(2个异常都抛出)
var2.addSuppressed(var11);
}
} else {
//如果代码没有异常,close异常就是最后的catch块中的var14
is.close();
}
}
}
} catch (IOException var14) {
var14.printStackTrace();
}
}
}
为什么要设计一个 addSuppressed(Throwable e) (添加被压制异常)的方法呢?
是为了防止异常信息的丢失,将2个异常都抛出。
11、重写桥接(synthetic bridge)
方法重写时对返回值分两种情况:
1、父子类的返回值完全一致
2、子类返回值可以是父类返回值的子类(JVM在编译的时候会进行优化)
synthetic bridge是JVM内部自动生成的合成方法,对我们是不可见的。这个方法允许方法同名,并且参数一致,并不会违反方法重载的规则。作为一种桥接手段,让子类方法重写真真符合重写的规则。
12、匿名内部类
匿名内部类实际上就是生成一个实现类。
案例:
匿名内部类引用外部变量的时候,这个变量必须为常量(final)。
把外部变量x的值作为参数传给构造方法。
所以外部变量的值不应该发生变化,如果变化,那么实现类中的val$x的值就没办法跟着一起变化,就会导致值不一致。
解决方法:使用数组或者集合存数据。
改变匿名内部类的变量
interface A {
void run();
}
public class Test {
public static void main(String[] args) {
int[] arr = new int[1];
arr[0] = 1;
for (int i = 0; i < 5; i++) {
A a = new A() {
@Override
public void run() {
System.out.println(arr[0]);
}
};
a.run();
arr[0]++;
}
}
}
以上是关于JVM day04 语法糖的主要内容,如果未能解决你的问题,请参考以下文章