文章目录
四、可变参数
1.案例代码
代码如下:
public class Demo4 {
public static void foo(String... args) {
//将args赋值给arr,可以看出String...实际就是String[]
String[] arr = args;
System.out.println(arr.length);
}
public static void main(String[] args) {
foo("hello", "world");
}
}
可变参数 String… args 其实是一个 String[] args , java 编译器会在编译期间将上述代码转换。
2.编译优化
代码如下:
public class Demo4 {
public Demo4 {}
public static void foo(String[] args) {
String[] arr = args;
System.out.println(arr.length);
}
public static void main(String[] args) {
//这里其实就相当于一个字符串数组,可以将参数都囊括进去。
foo(new String[]{"hello", "world"});
}
}
注意
:如果调用的是foo()
,即未传递参数时,等价代码为foo(new String[]{})
,创建了一个空数组,而不是直接传递的null
。
五、foreach
1.案例代码
代码如下:
public class Demo5 {
public static void main(String[] args) {
//数组赋初值的简化写法也是一种语法糖。
int[] arr = {1, 2, 3, 4, 5};
for(int x : arr) {
System.out.println(x);
}
}
}
数组赋初值的简化写法也是一种语法糖。
2.编译优化
代码如下:
public class Demo5 {
public Demo5 {}
public static void main(String[] args) {
//优化后
int[] arr = new int[]{1, 2, 3, 4, 5};
//优化后,底层是for循环
for(int i=0; i<arr.length; ++i) {
int x = arr[i];
System.out.println(x);
}
}
}
foreach
底层就是for循环
。
六、集合使用foreach
1.案例代码
代码如下:
public class Demo5 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
for (Integer x : list) {
System.out.println(x);
}
}
}
集合要使用foreach,需要该集合类实现Iterable接口
,因为集合的遍历需要用到迭代器Iterator
。
2.编译优化
代码如下:
public class Demo5 {
public Demo5 {}
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
//获得该集合的迭代器
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()) {
Integer x = iterator.next();
System.out.println(x);
}
}
}
七、switch字符串
1.案例代码
代码如下:
public class Demo6 {
public static void main(String[] args) {
String str = "hello";
switch (str) {
case "hello" :
System.out.println("h");
break;
case "world" :
System.out.println("w");
break;
default:
break;
}
}
}
2.编译优化
代码如下:
public class Demo6 {
public Demo6() {
}
public static void main(String[] args) {
String str = "hello";
int x = -1;
//通过字符串的hashCode+value来判断是否匹配
switch (str.hashCode()) {
//hello的hashCode
case 99162322 :
//再次比较,因为字符串的hashCode有可能相等
if(str.equals("hello")) {
x = 0;
}
break;
//world的hashCode
case 11331880 :
if(str.equals("world")) {
x = 1;
}
break;
default:
break;
}
//用第二个switch在进行输出判断
switch (x) {
case 0:
System.out.println("h");
break;
case 1:
System.out.println("w");
break;
default:
break;
}
}
}
过程分析:
- 在编译期间,单个的switch被分为2个switch。
第一个: switch (str.hashCode()) {...}
第二个: switch (x) {...}
- 第一个switch使用hashCode获取第二个switch的入口值。
这里使用的是hashCode+equals判断字符串是否相等。hashCode提高效率
,equals防止hashCode冲突
。
//通过字符串的hashCode+value来判断是否匹配
switch (str.hashCode()) {
//hello的hashCode
case 99162322 :
//再次比较,因为字符串的hashCode有可能相等
if(str.equals("hello")) {
x = 0;
}
....
}
- 第二个switch获取到第一个switch获取到的值,获取最终用户想要获取的值。
//用第二个switch在进行输出判断
switch (x) {
case 0:
System.out.println("h");
break;
....
}
七、switch枚举
1.案例代码
代码如下:
public class Demo7 {
public static void main(String[] args) {
SEX sex = SEX.MALE;
switch (sex) {
case MALE:
System.out.println("man");
break;
case FEMALE:
System.out.println("woman");
break;
default:
break;
}
}
}
//枚举类
enum SEX {
MALE, FEMALE;
}
2.编译优化
代码如下:
public class Demo7 {
/**
* 定义一个合成类(仅 jvm 使用,对我们不可见)
* 用来映射枚举的 ordinal 与数组元素的关系
* 枚举的 ordinal 表示枚举对象的序号,从 0 开始
* 即 MALE 的 ordinal()=0,FEMALE 的 ordinal()=1
*/
static class $MAP {
//数组大小即为枚举元素个数,里面存放了case用于比较的数字
static int[] map = new int[2];
static {
//ordinal即枚举元素对应所在的位置,MALE为0,FEMALE为1
map[SEX.MALE.ordinal()] = 1;
map[SEX.FEMALE.ordinal()] = 2;
}
}
public static void main(String[] args) {
SEX sex = SEX.MALE;
//将对应位置枚举元素的值赋给x,用于case操作
int x = $MAP.map[sex.ordinal()];
switch (x) {
case 1:
System.out.println("man");
break;
case 2:
System.out.println("woman");
break;
default:
break;
}
}
}
enum SEX {
MALE, FEMALE;
}
过程分析:
- 在底层会生成一个合成类,仅
JVM
可见。 - 映射枚举的 ordinal 与数组元素有对应关系,
- ordinal枚举元素对应所在的位置,MALE为0,FEMALE为1
-
将对应位置枚举元素的值赋予x
,进行case操作。
本博客根据黑马JVM课程所总结。