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_10 类加载与字节码技术(编译期处理——语法糖)

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

JVM:Java中的语法糖

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

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

从jvm角度来解析java语法糖