javap命令行分析揭示boolean的本质的虚拟机指令

源代码

public class BooleanTest {
    public static void main(String[] args) {
        boolean a = true;
        boolean b = false;
        System.out.println(a);
        System.out.println(b);
    }
}

编译

>javac BooleanTest.java

执行

>java BooleanTest
true
false

反汇编

>javap -c BooleanTest
Compiled from "BooleanTest.java"
public class BooleanTest {
  public BooleanTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_0
       3: istore_2
       4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       7: iload_1
       8: invokevirtual #3                  // Method java/io/PrintStream.println:(Z)V
      11: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      14: iload_2
      15: invokevirtual #3                  // Method java/io/PrintStream.println:(Z)V
      18: return
}

main()的虚拟机指令分析

iconst_1

上面的指令表示先生成一个常量,值为1,实际上是true。

istore_1

上面的指令表示将常量1赋值给第一个变量(在jshell里就是$1)

iconst_0

上面的指令表示先生成一个常量,值为0,实际上是false。

istore_2

上面的指令表示将常量0赋值给第二个变量(在jshell里就是$2)

getstatic

由于System.out.println()其中的System.out其实是java.lang.System中的一个静态的属性,所以这个指令顾名思义,就是获取这样一个静态属性。
这个System.out的类型其实是java.io.PrintStream,这点我们在之前的文章中也说过了,感兴趣的可以查看源码自行了解。

iload_1

将$1压栈,加到虚拟机栈空间中。

invokevirtual

调用System.out的println(),打印$1的值,输出true。

getstatic

再次获取System.out

iload_2

将$2压栈,加到虚拟机栈空间中。

invokevirtual

调用System.out的println(),打印$2的值,输出false。

return

main()返回值为void,使用return结束方法,相当于C/C++中int main()最后的return 0。

深入探讨boolean字节数

引自——http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html的说明:

boolean: The boolean data type has only two possible values: true and false. Use this data type for simple flags that track true/false conditions. This data type represents one bit of information, but its “size” isn’t something that’s precisely defined.

【翻译】
布尔值:布尔数据类型只有两个可能的值:true和false。 将此数据类型用于跟踪真/假条件的简单标志。 此数据类型代表一小部分信息,但其“大小”并不是精确定义的。

其实学过C语言的大家也知道,C中没有boolean/bool这种类型的变量,只需要使用0/1即可,经过测试我们也知道,哪有boolean这种东西啊?计算机中所有的运算都是0/1序列,怎么存在真正的boolean?

同样的,既然本身不存在,那其占用空间与实现方式有关,而实现方式由编译器、虚拟机等决定。

《Java虚拟机规范》书中说到:
虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位。

结论

  1. boolean类型实际不存在,在JVM中使用0/1表示false/true。
  2. boolean类型占用字节数没有被规定,这与编译器、虚拟机等有关。
  3. boolean类型在规范标准的虚拟机中占4个字节;但规定boolean数组中每一个boolean使用1个字节的byte表示以节约空间。(所以说,网传1字节特别是1bit的,基本认定是骗人的)

再思考:4字节/1字节?

Java有四种整数类型,byte(1 bit)、short(2 bits)、int(4 bits)、long(8 bits)。

已知boolean就是使用0/1整数表示的前提下,使用byte表示boolean可以节约空间,这对于长数组或者大规模多维数组来说还是挺重要的。

而使用int表示普通boolean,看似消耗了更多的空间,但实际上考虑到在32位/64位的机器上进行运算,int显然更方便一些,对计算本身很友好。

这种选择正是体现了计算机科学中的“Trade Off”,我在很多文章里都提到过,很orz这个词。我们还是要在不完美中选择最适合具体情况的最优解啊orz。

发布了645 篇原创文章 · 获赞 1334 · 访问量 57万+

猜你喜欢

转载自blog.csdn.net/weixin_43896318/article/details/104627729