无题

(以下测试均采用 hotspot 虚拟机)讨论两个问题:

finally

以下代码输出什么

import org.junit.Test;

public class NoneTest1 {

    public String code(){
        String str = "1";
        try {
            return str;
        }finally {
            str = "2";
        }
    }

    @Test
    public void test(){
        System.out.println(code());
    }

}

解释

switch

在空间允许的情况下,以下哪个test效率高

public class NoneTest2 {

    public int test1(int num){
        int res;
        switch (num){
            case 1:
                res = 1;
                break;
            case 2:
                res = 2;
                break;
            case 3:
                res = 3;
                break;
            default:
                res = 0;
        }
        return res;
    }

    public int test2(int num){
        int res;
        switch (num){
            case 1:
                res = 1;
                break;
            case 3:
                res = 3;
                break;
            case 2:
                res = 2;
                break;
            default:
                res = 0;
        }
        return res;
    }

    public int test3(int num){
        int res;
        switch (num){
            case 10:
                res = 10;
                break;
            case 30:
                res = 30;
                break;
            case 40:
                res = 40;
                break;
            default:
                res = 0;
        }
        return res;
    }

}

解释

解释

第一个问题

输出的是,并不会输出 2 ,原因在 oracle(此版本为jdk8) 官方已经给出来了

1

圈出来的一段的最后一句

# 如果 try 语句中包含return,则编译后的代码执行以下操作
If the try clause executes a return, the compiled code does the following:
# 保存返回值到局部变量表中
1.Saves the return value (if any) in a local variable.
# 执行 finally 代码
2.Executes a jsr to the code for the finally clause.
# 从 finally 返回时,返回保存在局部变量表中的值
3.Upon return from the finally clause, returns the value saved in the local variable.

所以在上方返回的是临时保存在局部变量表中的 str="1"

异常表

2

当字节码 3—5行出现异常时,直接跳转第 10 行

对应字节码

 0 ldc #2 <1>	#加载 “1” 到操作数栈
 2 astore_1		#保存到局部变量表 1 的位置(0位置是this)
 3 aload_1		#加载局部变量表 1 号位到操作数栈
 4 astore_2		#保存到 2 号位(对应上面第一句话,保存返回值到局部变量表中)
 5 ldc #3 <2>	#加载 “2” 到操作数栈
 7 astore_1		#保留给 1 号位,此时 1 号位为 “2”,2 号位依旧为1
 8 aload_2		#加载 2 号位
 9 areturn		#返回 2 号位
10 astore_3		#当出现异常时跳转到该位置,保存 异常 到 3 号位
11 ldc #3 <2>
13 astore_1
14 aload_3		#加载 3 号位异常
15 athrow		#抛出异常

所以可以看出在返回时做了一次复制操作,需要注意的是,如果返回的是对象,复制的是 对象地址值 ,而不是直接复制一份实例对象。

第二个问题

test1 和 test2 效率相同,都优于 test3

oracle switch 章节中,最后一句话说明了,在空间允许的情况下,tableswitch 更优于 lookupswitch

3

而要被编译成 tableswitch,The tableswitch instruction is used when the cases of the switch can be efficiently represented as indices into a table of target offsets.

当case可以有效的表示为目标偏移表中的索引时,采用tableswitch,简单来说,就是当 case 条件为连续的时候,采用 tableswitch,所以 test1、test2 会被编译成 tableswitch,虽然 test2 case条件并不是连续的,但是在编译的时候会进行排序然后采用 tableswitch。而 test3 采用的是 lookupswitch。

甚至存在如下代码采用的还是 tableswitch

public int test4(int num){
    int res;
    switch (num){
        case 1:
            res = 1;
            break;
        case 3:
            res = 3;
            break;
        case 4:
            res = 4;
            break;
        default:
            res = 0;
    }
    return res;
}
posted @ 2023-01-06 14:28  抱糖果彡  阅读(21)  评论(0编辑  收藏  举报