《深入理解Java虚拟机》-(实战)boolean类型在虚拟机中是如何处理的
这里先引出Java的8大基本类型。直接上图吧。
可以看到,除了boolean和char类型之外,越往下的类型的值域是包含以上的值域的。因此,从上面的基本类型转换成下面的基本类型,无需强制转换。关于它们的默认值,在内存中保存的都是0。
对于char类型,菜鸟喜鹊有些感悟,就是char类型转成int类型的例子很多。
今天上班忙里抽闲学习了一下"AC自动机"的实现,其中就是模式串构建tired树的时候的char类型处理的时候,直接使用它与'a'相减,得到数组下标的。这里也算是用了一个转换吧。还有String类里的indexOf(int n)也是。
读者有空可以去看看。
对于boolean类型,上图的表格里是true和false的值。可是,从jvm角度来看,可不一样。在这里,你可以参照我上一篇文章写的字节码文章改一下。将值iconst_1改成iconst_3,iconst_4,iconst_5看看有什么结果。再看看我这里的结论。
ok! talk is cheap,show you my code!
(以下操作在linux进行)
1.编写Foo.java
public class Foo {
static boolean boolValue;
public static void main(String[] args) {
boolValue = true; // 将这个 true 替换为 2 或者 3,再看看打印结果
if (boolValue) System.out.println("Hello, Java!");
if (boolValue == true) System.out.println("Hello, JVM!");
}
}
2.编译运行
[root@localhost tmp2]# javac Foo.java
[root@localhost tmp2]# java Foo
Hello, Java!
Hello, JVM!
3.查看class字节码(这里就不看了,就看boolValue的值就好了。上一篇文章中有演示过(https://www.cnblogs.com/chenscript/p/11343270.html))
4.修改常量值分别为4和5,编译并输出结果:
[root@localhost tmp2]# awk 'NR==1,/iconst_1/{sub(/iconst_1/,"iconst_4")} 1' Foo.jasm.1>Foo.jasm
[root@localhost tmp2]# java -jar ../asmtools.jar jasm Foo.jasm
[root@localhost tmp2]# java Foo
(改成4的时候,没有输出!)
[root@localhost tmp2]# awk 'NR==1,/iconst_1/{sub(/iconst_1/,"iconst_5")} 1' Foo.jasm.1>Foo.jasm
[root@localhost tmp2]# java -jar ../asmtools.jar jasm Foo.jasm
[root@localhost tmp2]# java Foo
Hello, Java!
Hello, JVM!
这里,我们就该查看一下字节码:
5.这里就贴关键部分的字节码吧。
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: iconst_4 //
1: putstatic #5 // Field boolValue:Z
4: getstatic #5 // Field boolValue:Z
7: ifeq 18
10: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
13: ldc #2 // String Hello, Java!
15: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
18: getstatic #5 // Field boolValue:Z
21: iconst_1 //
22: if_icmpne 33
25: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
28: ldc #1 // String Hello, JVM!
30: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
33: return
StackMapTable: number_of_entries = 2
frame_type = 18 /* same */
frame_type = 14 /* same */
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: iconst_5 //
1: putstatic #5 // Field boolValue:Z
4: getstatic #5 // Field boolValue:Z
7: ifeq 18
10: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
13: ldc #2 // String Hello, Java!
15: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
18: getstatic #5 // Field boolValue:Z
21: iconst_1 //
22: if_icmpne 33
25: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
28: ldc #1 // String Hello, JVM!
30: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
33: return
StackMapTable: number_of_entries = 2
frame_type = 18 /* same */
frame_type = 14 /* same */
总结上面的输出:
如果单从肉眼看,按照上一篇的学习,改写成4和5的时候,ifeq比较的值是0,0与4、5怎么可能匹配得上?但是在改成iconst_5的时候,虚拟机就判断是不相等,然后输出“Hello,Java”,改成4的时候,就相等,直接跳转。
为什么呢?
这里面是有点玄机。
根据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.
官方说:
布尔类型:布尔数据类型只有两个可能的值:真和假。使用此数据类型为跟踪真/假条件的简单标记。这种数据类型就表示这一点信息,但是它的“大小”并不是精确定义的。
由于笔者实力有限,也只能到这一步了。但根据实际操作看推测的话,这个二进制有关,也就是比较的值都是使用二进制的最低位进行比较的。也就是,4的二进制100,5 的二进制是101,取最低位,就是0和1了。这里机器码中的0是false,1是true~就这样吧~
Java基本类型在局部变量区(属于Java方法栈)和堆中的存储大小是有区别的:
主要表现于:boolean、byte、char、short 这几个的存储大小根据环境不同而不同
局部变量区:在32位的hotspot中都是占用4个字节,而在64位的hotspot中占用8个字节。
堆:byte、char、short分别占一字节、两字节、两字节。(也就是跟这些的值域相吻合的~~)
以上~
原文地址:https://www.cnblogs.com/chenscript/p/11349201.html
- 程序猿python学习AIphaZero,TensorFlow强化学习AI游戏,100行代码运行看看!
- awk中NF的使用
- tar.gz 解压
- Python&机器学习之项目实践
- JAVA CDI 学习(5) - 如何向RESTFul Service中注入EJB实例
- mysql5.7 column cannot be null
- 区块链大热 价值近20万的Matrix.io被启用
- 比特币科普之什么是区块高度?
- 如何正确并快速理解MapReduce
- mysqldump的简单使用
- mac:在当前文件夹打开terminal终端
- 斯诺登研发黑客警报App上架 监测功能引发争议
- JMS + jboss EAP 6.2 示例
- Maven Compilation error [package org.testng.annotations does not exist]
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- LeetCode53|搜索二维矩阵II
- LeetCode54|二叉树的层次遍历
- LeetCode55|二叉树的层次遍历II
- LeetCode56|二叉树的层平均值
- LeetCode57|二叉树的锯齿形层次遍历
- LeetCode58|N叉树的层序遍历
- 技术创作101训练营-CRC校验没那么难
- 栈与队列:有没有想过计算机是如何处理表达式的?
- 栈与队列:滑动窗口里求最大值引出一个重要数据结构
- 栈与队列:求前 K 个高频元素和队列有啥关系?
- 手写一个抖音视频去水印工具,千万别刚一个程序员
- ApplicationListener接口实践
- 浅谈vue+element全局loading加载
- LeetCode59|重复N次的元素
- 谈Vue组件的is特性