t != (t = tail) 可以为 true ?!

2020-02-27  本文已影响0人  ________方块丶

这个表达式出现在ConcurrentLinkedQueue的源码中,就是这么简短的一个表达式,搞的我是一头雾水,一脸懵逼。总是产生一种错觉,就是它应该永远为“false”。(在我心里括号最先执行,给t赋值tail,在比较左边t和右边t。)

下面就来分析下 t != (t = tail) 为啥子可以为true.

模拟一下场景:
public class Test{
    public static void main(String[] args) {
        Object t = new Object();
        Object tail = new Object();
        boolean eqs = t != (t = tail);
        System.out.println(eqs);
    }
}
从JVM指令方面寻找答案:

(用了Maven),执行一下这个main方法,在target下找到编译的Test.class,idea右键 Open In Terminal,在底部Terminal中,输入:

javap -c -v Test.class

<!--重点选项-->
-version                 版本信息,其实是当前javap所在jdk的版本信息,不是class在哪个jdk下生成的。
-v  -verbose             输出附加信息(包括行号、本地变量表,反汇编等详细信息)
-l                       输出行号和本地变量表
-p  -private             显示所有类和成员
-c                       对代码进行反汇编
-s                       输出内部类型签名

javap是jdk自带的反解析工具。它的作用就是根据class字节码文件,反解出当前类对应的code区(汇编指令)、本地变量表、异常表和代码行偏移量映射表、常量池等等信息.

反解析出JVM指令代码如下:

# 这里咱们重点看main方法和局部变量表

public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=4, args_size=1
         0: new           #2                  // class java/lang/Object
         3: dup
         4: invokespecial #1                  // Method java/lang/Object."<init>":()V
         7: astore_1
         8: new           #2                  // class java/lang/Object
        11: dup
        12: invokespecial #1                  // Method java/lang/Object."<init>":()V
        15: astore_2
        16: aload_1
        17: aload_2
        18: dup
        19: astore_1
        20: if_acmpeq     27
        23: iconst_1
        24: goto          28
        27: iconst_0
        28: istore_3
        29: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        32: aload_1
        33: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        36: return
...
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      37     0  args   [Ljava/lang/String;
            8      29     1     t   Ljava/lang/Object;
           16      21     2  tail   Ljava/lang/Object;
           29       8     3   eqs   Z

综上可知,boolean eqs = t != (t = tail) 其实类似于将tail赋值给t(局部变量表中t已经是tail的值 了),再用旧的t(栈里面还是旧的,因为在赋值之前,值已经入栈了)和tail(栈中还剩的一个tail的值)比较,因此为true。

(感谢以上博客,提供参考)

个人对这块也是一知半解,哪里表述的有误,请一定指出,赐我一场教化。

上一篇 下一篇

猜你喜欢

热点阅读