JVM之基本类型

最近在看JVM方面的东西,其中看到关于基本类型方面的一些讲解,在早之前未曾留意,今天这里记录一下。

在java语言规范中boolean类型只有true和false,但是jvm不能直接使用true和false。在jvm规范中,boolean类型被映射为int,true被映射为1,false被映射为0。也这样一来,在编译而成的字节码文件中,除了字段和传入参数外,基本上看不到boolean的痕迹了。

java code:

public class Test {
    public static void main(String[] args) throws Exception {
        boolean flag = true;
        if(flag) {
            System.out.println("Hello World");
        }
        if(flag == true) {
            System.out.println("Hello JVM");
        }
    }
}

-----------------------------------------------------------------------------------
javap -v Test.class

public static Method main:"([Ljava/lang/String;)V"
	throws java/lang/Exception
	stack 2 locals 2
{
		iconst_1; // 对应 true
		istore_1;
		iload_1;
		ifeq	L14;
		getstatic	Field java/lang/System.out:"Ljava/io/PrintStream;";
		ldc	String "Hello World";
		invokevirtual	Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
	L14:	stack_frame_type append;
		locals_map int;
		iload_1;
		iconst_1;
		if_icmpne	L27;
		getstatic	Field java/lang/System.out:"Ljava/io/PrintStream;";
		ldc	String "Hello JVM";
		invokevirtual	Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
	L27:	stack_frame_type same;
		return;
}

除了boolean之外,java还有byte,char,short,int,long,float,double。在这些类型中boolean和char是无符号类型,在不违反约束的情况下,boolean的取值范围是0或1,char的取值范围是[0,65535]。

由于boolean和其他类型有点不同,这里先验证一下,对于boolean变量除了0和1之外,像2,3等这样的值也是可以直接操作。

这里使用asmtools来进行验证,需要jdk8及以上。

前往下载asmtools源代码

$ echo 'public class Test {
    public static void main(String[] args) throws Exception {
        boolean flag = true;
        if(flag) {
             System.out.println("Hello World");
        }
         if(flag == true) {
            System.out.println("Hello JVM");
        }
    }
 }' Test.java

$ javac Test.java

$ java -jar asmtools.jar jdis Test.class > Test.jsam.1

// 下面的命令是将boolean赋值为3
$ awk 'NR==1,/iconst_1/{sub(/iconst_1/,"iconst_3")} 1' Test.jasm.1 > Test.jasm

# java -jar asmtools.jar jasm Test.jasm

$ java Test

输出 Hello World

------------------------------------------------

上面最终的Test字节码如下:

public static void main(java.lang.String[]) throws java.lang.Exception;
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Exceptions:
      throws java.lang.Exception
    Code:
      stack=2, locals=2, args_size=1
         0: iconst_3  // 源文件编译后这里是1,通过awk 修改为3
         1: istore_1
         2: iload_1
         3: ifeq          14   // 操作数栈顶等于0在跳转到14行
         6: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
         9: ldc           #2                  // String Hello World
        11: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        14: iload_1
        15: iconst_1
        16: if_icmpne     27   // 两个int变量不相等就跳转到27行
        19: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        22: ldc           #1                  // String Hello JVM
        24: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        27: return
      StackMapTable: number_of_entries = 2
        frame_type = 252 /* append */
          offset_delta = 14
          locals = [ int ]
        frame_type = 12 /* same */
}

在jvm中,栈帧中的两个主要组成部分:局部变量区和操作数栈。局部变量区等价于一个数组,可通过正整数来索引。除了long和double值需要两个数组单元,其他基本类型及引用类型均是占用一个单元。也即是说boolean,byte,char,short在栈上占用的空间和int是一样的,和引用类型也一样。

这种情况仅存在于局部变量,而不会出现在存储于堆区的字段或数组单元上,在堆上而言,上述四种类型占用的空间与其值域相吻合。

对于byte,boolean,char,short而言,从堆区加载和存储这些字段或数组单元时分别会进行 符合扩展 和 掩码操作,这里boolean或boolean数组来说 比较特殊。

在HotSpot中boolean占用一个字节(堆区中用byte映射boolean),对于基本类型的运算几乎都是在栈上进行的,上面说到,在栈中,boolean是占用和int一样的,因此对boolean类型(堆区中:字段或数组)写入时需要进行掩码操作,也就是取最后一位的值存入boolean字段或数组中。比如说,栈中的值是2,在存入到boolean字段或数组中的值是0,栈中是3,则存入的是1。

因此对于上面用int验证boolean的列子中,将 flag 变量提到main方法外面作为字段时,

使用iconst_2时,将不会打印出任务字符,使用iconst_3时,会打印两条字符。

The end!!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值