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 语法糖的主要内容,如果未能解决你的问题,请参考以下文章

JVM:Java中的语法糖

python学习day07 高阶函数 装饰器 语法糖

JVM -- 编译器处理;语法糖

JVM -- 编译器处理;语法糖

JVM_10 类加载与字节码技术(编译期处理——语法糖)

JVM_10 类加载与字节码技术(编译期处理——语法糖)