JAVA之语法糖

一、概念

编译器是一种计算机程序, 它主要的目的是将便于人编写、阅读、维护的高级计算机语言所写的源代码程序, 翻译为计算机能解读、运行的低阶机器语言的程序, 即可执行文件。而 javac 就是java语言中的编译器, 它用于将 .java 文件转换成JVM能识别的 .class 字节码文件, 反编译则是将 .class 文件转换成 .java 文件。

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·兰丁发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用。语法糖让程序更加简洁,有更高的可读性。

java中的语法糖只存在于编译期, 在编译器将 .java 源文件编译成 .class 字节码时, 会进行解语法糖操作, 还原最原始的基础语法结构。关于反编译工具, 其实在JDK中自带了一个javap命令,可以使用反编译查看语法糖编译做了什么。

二、语法糖例子

1、字符串拼接

        String string = "";
		String[] strs = {"iniy","init","zzz"} ;
		for (String str : strs) {
			string += str ; //编译时语法糖每次循环都会创建一个StringBuilder
		}

编译后

当我们使用+号进行字符串拼接操作时, 编译时会自动创建一个StringBuilder对象。所以当在循环中拼接字符串时, 应避免使用+号操作, 否则每次循环都会创建一个StringBuilder对象再回收, 造成较大的开销。

2、条件编译

        if(false) {
			System.out.println("语法糖会把这端代码消除");
		}else {
			System.out.println("最终保留");
		}

//编译后
        System.out.println("最终保留");

javac编译器在编译时期的解语法糖阶段, 会将条件分支不成立的代码进行消除。

3、断言

public void assertTest(String s) {
    assert (!s.equals("Fred"));
    System.out.println(s);
}

编译后

 当断言结果为true时, 程序继续正常执行, 当断言结果为false时, 则抛出AssertionError异常来打断程序的执行

4、可变参数

public void varargsTest(String ... arr) {
    for (String s : arr) {
        System.out.println(s);
    }
}

编译后

可变参数其实就是一个不定长度的数组, 数组长度随传入方法的对应参数个数来决定。可变参数只能在参数列表的末位使用。

5、枚举与Switch语句、字符串与Switch

6、自动装箱、自动拆箱

public Double autoBoxingTest(Integer i, Double d) {
    return d + i;
}

首先我们知道, 基本类型与包装类型在某些操作符的作用下, 包装类型调用valueOf()方法的过程叫做装箱, 调用xxxValue()方法的过程叫做拆箱。所以上面的结果很容易看出, 先对两个包装类进行拆箱, 再对运算结果进行装箱。

关于Integer

		Integer integer = new Integer(null) ;
		
//		Ingeter 源码
		public Integer(String s) throws NumberFormatException {
	        this.value = parseInt(s, 10);
	    }
		public static int parseInt(String s, int radix)
                throws NumberFormatException
    {
        if (s == null) {
            throw new NumberFormatException("null");
        }
	}

执行此代码会报错,因为Integer初始化的时候会自动给内部类的int value赋值,null会抛异常

        Integer a = new Integer(1000) ;
		Integer b = new Integer(1000) ;
		Integer c = new Integer(100) ;
		Integer d = new Integer(100) ;
		Integer e = 100, f = 100;
		Integer g = 1000, h = 1000;
		Integer i = Integer.valueOf(100);
		
		System.out.println(a == b); //false
		System.out.println(c == d); //false
		System.out.println(e == f); //true
		System.out.println(g == h); //false
		System.out.println(a.equals(b));  //true
		System.out.println(a.intValue() == b.intValue()); //true
		System.out.println(i == c); //false
		System.out.println(i == e); //true
		
		//equals会先进行数值类型对比,在进行值对比
		public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
		}
		// Integer e = 100 等同于 Integer e = Integer.valueOf(100);
		// IntegerCache.low = -128 IntegerCache.high=127
		public static Integer valueOf(int i) {
	        if (i >= IntegerCache.low && i <= IntegerCache.high)
	            return IntegerCache.cache[i + (-IntegerCache.low)];
	        return new Integer(i);
	    }

注意:1、Integer和Integer对比可以用equals,Integer和int可以用intvalue拆箱。

            2、new Integer会创建一个类对象,是不相等的,静态方法valueof(或者直接装箱)是有一个IntegerCache保存-128到127之间的数值,是相等的。

7、泛型擦除

public void genericEraseTest() {
    List<String> list =  new ArrayList<String>();
}

在JVM中没有泛型这一概念,  只有普通方法和普通类, 所有泛型类的泛型参数都会在编译时期被擦除, 所以泛型类并没有自己独有的Class类对象比如List<Integer>.class, 而只有List.class对象

8、增强for循环

             String[] qingshanli = {"a", "b", "c", "d"};  
		    List<String> list =  Arrays.asList(qingshanli);
		    for (String s : list) {
		        s  = "xxxxx" ;
		    }
		    System.out.println(list);
		    for(int i = 0; i<list.size();i++) {
		    	list.set(i,"xxxxx") ;
		    }
		    System.out.println(list);
//结果
[a, b, c, d]
[xxxxx, xxxxx, xxxxx, xxxxx]

 增强for循环的底层其实还是通过迭代器来实现的, 这也就解释了为什么增强for循环中不能进行增删改操作。

不用定义局部变量以及判断list长度的循环成为增强for循环。

9、try-with-resources语句

传统关闭资源方式,try-catch-finally,避免finally出现异常还要try-catch,很繁琐

public static void main(String[] args) {
    FileInputStream inputStream = null;
    try {
        inputStream = new FileInputStream(new File("test"));
        System.out.println(inputStream.read());
    } catch (IOException e) {
        throw new RuntimeException(e.getMessage(), e);
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }
}

try-with-resource语法

public static void main(String[] args) {
    try (FileInputStream inputStream = new FileInputStream(new File("test"))) {
        System.out.println(inputStream.read());
    } catch (IOException e) {
        throw new RuntimeException(e.getMessage(), e);
    }
}

把流的初始化放在了try()里面,在语法糖编译时会还原成try-catch-finally

10、JDK10 局部变量

    //初始化局部变量  
    var string = "qingshanli";

编译时会把var局部变量编译成真的数据类型,因为JAVA是强语言。var i = "10"-1; 这种可以在js中实现,JAVA不可以。

jdk10 var只允许初始化值,且不为null。因为外部调用时给var放不同的数值类型会让JVM不知道到底是什么数据类型。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值