• 语法糖


    编译期处理(语法糖)

    1. 所谓语法糖,就是指Java编译器在java源码编译为class字节码过程中,自动生成和转换的一些代码,为开发提供便利
    2. 通过javap 指令,反编译class文件,就可以看到编译器的编译期处理

    默认构造器

    一个类没有写构造方法时,会有一个默认的无参构造方法,这是编译器帮我们加上的

    public class Main{
        public static void main(String[] args) {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    自动拆装箱机制

    这个特性是jdk5开始加入的,对每个基本数据类型所对应的包装类的转换提供便利,编译器会自动生成调用valueOf方法的代码来进行转换

    public class Main{
        public static void main(String[] args) {
            Integer i = 1;
            int i2 = i;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    泛型擦除

    Java泛型是1.5引入的新特性,可以通过泛型来表示任意的类型,提高代码的复用性;但是泛型是不会保留到运行期的,在编译期,编译器就会对泛型进行擦除;实际的操作都会当作Object对象来进行操作

    public class Main{
        public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            //实际上是调用的void add(Object obj)
            list.add(1);
            //实际上是调用的Object get(int index)
            int i = list.get(0);
            //相当于编译器帮我们做了(Object)1和(Integer)list.get(0)的强制类型转换的步骤
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    泛型反射

    泛型信息虽然被擦除了,不会出现在字节码中,但是反编译后出现了一个LocalVariableTypeTable可以看到泛型,通过反射可以得到方法的参数和返回值的泛型信息

    public class Main{
        public static void main(String[] args) throws NoSuchMethodException {
            Method method = Main.class.getMethod("test", List.class, Map.class);
            // 得到方法的参数类型,即List和Map
            Type[] types = method.getGenericParameterTypes();
            for (Type type:types){
                // 转化为参数类型对象
                ParameterizedType parameterizedType = (ParameterizedType) type;
                System.out.println("原始类型:"+parameterizedType.getRawType());
                // 得到泛型类型
                Type[] arguments = parameterizedType.getActualTypeArguments();
                for (int i = 0; i < arguments.length; i++) {
                    System.out.printf("泛型参数[%d] - %s\n",i,arguments[i]);
                }
            }
        }
    
        public Set<Integer> test(List<String> list, Map<Integer,Object> map){
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    可变参数

    可变参数也是jdk5开始加入的新特性,可变参数实际上在编译期会被转换成一个数组

    public class Main{
        public static void main(String[] args){
            test("123","456");
        }
    
        private static void test(String ...args){
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    foreach循环

    jdk5引入,遍历数组、集合时,可以通过foreach的方式

    数组

    public class Main{
        public static void main(String[] args){
            // 直接赋值数组的方式也是一种语法糖,会转换为new int[]{1,2,3}的形式
            int[] nums = {1,2,3};
            for (int num : nums) {
                System.out.println(num);
            }
            // 上面这种方式会被转换为
            for(int i=0;i<nums.length;i++{
            	int nums = nums[i];
            	System.out.println(num);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    集合

    public class Main{
        public static void main(String[] args){
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            for (Integer i : list) {
                System.out.println(i);
            }
    
            // 会被转换成这样
            Iterator<Integer> it = list.iterator();
            while(it.hasNext()){
                Integer i = it.next();
                System.out.println(i);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    switch字符串和枚举类

    从jdk7开始,switch可以用作字符串和枚举类(原生的switch并不支持),这个功能也是语法糖

    字符串

    public class Main{
        public static void main(String[] args){
            test("hello");
        }
    
        private static void test(String str){
            switch (str){
                case "hello":
                    System.out.println("1");
                    break;
                case "bye":
                    System.out.println("2");
            }
    
            // 会变成被转换成下面的形式
            byte x = -1;
            switch(str.hashCode()){
                // "hello"的hashCode
                case 99162322:
                    if("hello".equals(str)){
                        x=0;
                    }
                    break;
                    // "bye"的hashCode
                case 98030:
                    if("bye".equals(str)){
                        x = 1;
                    }
            }
            switch(x){
                case 0:
                    System.out.println("1");
                    break;
                case 1:
                    System.out.println("2");
                    break;
            }
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    在这里插入图片描述
    在这里插入图片描述

    枚举类

    public class Main{
        public static void main(String[] args){
            System.out.println(Sex.values().length);
        }
    
        private static void test(Sex sex){
            switch (sex){
                case MALE:
                    System.out.println("male");
                    break;
                case FEMALE:
                    System.out.println("female");
                    break;
            }
        }
    
        // 上面会被转换成下面这样
        static class $MAP{
            static int[] map = new int[2];
            static{
                map[Sex.MALE.ordinal()] = 1;
                map[Sex.FEMALE.ordinal()] = 2;
            }
        }
    
        private static void test(Sex sex){
            int x = $MAP.map[sex.ordinal()];
            switch (x){
                case 1:
                    System.out.println("male");
                    break;
                case 2:
                    System.out.println("female");
                    break;
            }
        }
    }
    
    enum Sex{
        MALE,FEMALE
            }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    枚举类

    枚举实际上也是一个class
    原代码

    enum Sex{
    	MALE,FEMALE
    }
    
    • 1
    • 2
    • 3

    编译期处理后

    pulbic final class Sex extends Enum<Sex> {
    	public static final Sex MALE;
    	public static final Sex FEMALE;
    	public static final Sex[] $VALUES;
    	static {
    		MALE = new Sex("MALE",0);
    		FEMALE = new Sex("FEMALE",1);
    		$VALUES = new Sex[]{MALE,FEMALE};
    	}
    	private Sex(String name,int ordinal){
    		super(name,ordinal);
    	}
    	public static Sex[] values(){
    		return$VALUES.clone();
    	}
    	public static Sex valueOf(String name){
    		return Enum.valueOf(Sex.class,name);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    try-with-resources

    jdk开始,新增了堆需要关闭的资源处理的特殊语法,即try-with-resources;要求其中资源对象需要实现AutoCloseable接口,例如InputStream、OutputStream、Connection、Statement、ResultSet等接口都实现了AutoCloseable,使用try-with-resources就可以不用写finally语句块,编译器会自动生成关闭资源的代码
    原代码

    try(InputStream is = new FileInputStream("d:\\1.txt")) {
    	
    }catch(IOExeption e){
    	e.printStackTrace();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    编译期处理后代码

    try{
    	InputStrem is = new FileInputStream("d:\\1.txt");
    	Throwable t = null;
    	try{
    	
    	}catch(Throwable e1){
    		t = e1;
    		throw e1;
    	}finally {
    		// 判断资源是否为空
    		if(is!=null) {
    		// 如果代码有异常
    			if(t!=null){
    				try{
    					is.close();
    				}catch (Throwable e2){
    					// 如果close出现异常,作为被压制异常添加
    					t.addSuppressed(e2);
    				}
    			}else{
    				// 如果代码没有异常,close出现了异常就是catch中的e,所以不需要再catch
    				is.close();
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    addSuppressed的方法设计是为了防止异常丢失,在异常跟踪栈中可以看到所有的异常

    方法重写时的桥接方法

    方法重写的返回值分两种情况:

    1. 父子类方法返回值相同
    2. 子类返回值是父类返回值的子类
      原代码
    class A{
    	public Number m(){
    		return 1;
    	}
    }
    class B extends A{
    	@Override
    	public Integer m(){
    		return 2;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    经过编译期处理后

    class B extends A{
    	public Integer m(){
    		return 2;
    	}
    	// 这个方法才是重写父类方法的,这是一个桥接方法,synthetic bridge关键字只有虚拟机内部使用,对开发者不可见
    	public synthetic bridge Number m(){
    		return m();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    匿名内部类

    源代码

    public class Main{
    	public static void main(String[] args){
    		Runnable runnable = new Runnable(){
    			@Override
    			public void run(){
    				
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    经过编译期转换后

    final class Main$1 implements Runnable{
    	Main$1(){}
    	public void run(){
    	}
    }
    public class Main{
    	public static void main(String[] args){
    		Runnable runnable = new Main$1();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    动作活体检测能力,构建安全可靠的支付级“刷脸”体验
    程序链接和加载
    useEffect 的监听原理
    Centos7 系统下使用telnet远程登录
    paramiko 3
    [Linux系统编程]_网络编程(五)
    r9 5900hx和i9 12900h哪个好
    2023/8/8 下午10:42:04 objectarx
    KVM虚拟网络概述
    windows系统手把手教你安装python虚拟环境
  • 原文地址:https://blog.csdn.net/m0_48468380/article/details/126919761