从包装类的自动拆(装)箱小案例 看Java中的语法糖
引入案例
//语法糖
//比较的是对象地址
Integer a = Integer.valueOf(211);
Integer b = Integer.valueOf(211);
System.out.print(a == b); //false
Integer f1 = 110;
Integer f2 = Integer.valueOf(110);
System.out.print(f1 == f2)//true
//自动拆箱, 比较的是值
int c = 211;
System.out.print(a == c)//true
结论: f1 == f2 的执行结果是 true ;
原因是 Integer 内部用到 享元模式 的设计,对 -128 到 127 之间的数字做了缓存;
首先: 使用 Integer f1 = 110 方式赋值时, Java默认通过 valueOf 对 110 这个数字进行装箱操作, 把数字 110 封装成 封装类型Integer,触发缓存机制,使得 f1 和 f2 指向同一个Integer地址空间 ;
其次: Integer内部设计, 享元模式的核心思想 通过复用对象 ,减少对象的创建数量, 从而减少内存占用和性能提升;
Integer 内部维护了一个 Integercache , 缓存 -128 到 127 该区间数值对应的 Integer 类型,一旦程序调用 valueOf 方法, 在该区间直接在 cache 缓存数组中取 Integer 对象, 否则会创建一个新对象.
Java 的 语法糖
语法糖
语法糖(Syntactic sugar),也叫做糖衣语法,是英国科学家发明的一个术语,指在计算机语言中添加的某种语法,这种语法对语言本身的功能来说没有什么影响,通常来说使用语法糖能够增加程序的可读性,方便程序员进行开发,提高开发效率, 从而减少程序代码出错的机会。说白了,语法糖就是对现有语法的一个封装。
因为 Java 代码需要运行在 JVM 中,JVM 是并不支持语法糖的,语法糖在程序编译阶段就会被还原成简单的基础语法结构,这个过程就是解语法糖。所以在 Java 中,真正支持语法糖的是 Java 编译器 .
Java编程语言提供了很多语法糖,简单整理一下,主要有下面几种常用的语法糖。
- 包装类自动装箱与拆箱
- Lambda表达式
- 字符串+号语法
- switch-case对String和枚举类的支持
- 支持泛型
- 枚举
- 内部类
- 增强for循环
- try-with-resource语法
10.数值字面量
方法变长参数
条件编译
断言
1. 自动装箱和自动拆箱
结合引入案例:
自动拆箱和自动装箱是一种语法糖,它说的是八种基本数据类型的包装类和对应基本数据类型之间的自动转换。简单的说,装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。
public static void main(String[] args) {
Integer x = 1;
int y = 2;
int res = a + b;
System.out.println(res);
}
public static void main(String[] args) {
// 自动装箱
Integer x = Integer.valueOf(1); //调用 invokestatic,相当于是编译器自动为我们添加了一下 Integer.valueOf 方法
byte y = 2;
//自动拆箱
int res = x.intValue() + y;//调用了 invokevirtual,相当于是编译器为我们添加了 Integer.intValue() 方法
System.out.println(res);
}
//用 javap -c 反编译
//调用 invokestatic 的时候,相当于是编译器自动为我们添加了一下 Integer.valueOf 方法从而把基本数据类型转换为了包装类型
//调用了 invokevirtual 的时候,相当于是编译器为我们添加了 Integer.intValue() 方法把 Integer 的值转换为了基本数据类型。
2. Lambda表达式
Lambda表达式的本质也是一个"语法糖",由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。
lambda表达式允许你通过表达式来代替功能接口。Lambda表达式还增强了集合库。 Java SE 8添加了2个对集合数据进行批量操作的包: java.util.function 包以及java.util.stream 包。 流(stream)就如同迭代器(iterator),但附加了许多额外的功能。 总的来说,lambda表达式和 stream 是自Java语言添加泛型(Generics)和注解(annotation)以来最大的变化。
//Lambda表达式基本语法1
(params) -> expression
//Lambda表达式基本语法2
(params) -> {
statements; }
// -> 箭头符号
// 左侧:Lambda表达式的参数列表。若只有一个参数左侧小括号可以不写。 Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型即“类型推断”(语法糖)。如果要写数据类型,就得全写。
// 右侧:Lambda表达式中所需要执行的功能,即Lambda体。右侧只有一条语句{}可以省略不写。
//举例
//无参数,无返回值。
Runnable r= ()-> System.out.println("HelloWorld!");
r.run();
//无参数,有返回值
() -> 5
//有参数,有返回值
Comparator<Integer> comparator = (x,y) -> {
System.out.println("函数式接口");
return Integer.compare(x,y);
}
Comparator<Integer> comparator = (x,y)-> Integer.compare(x,y);//如果右侧只有一条语句,return 也可以省略
//一参数,返回表达式
x -> 2 * X
//2参数, 返回乘积
(x,y) -> x * y
//2整型参数,返回和
(int a,int b) -> x+y
//参数字符串,无返回值,只打印
(</