在java中boolean类型占多少字节?
近看到一个特别有意思的面试题,就是面试官问boolean占多少字节。一时间还不知道如何回答。我们先来看看java中的基本数据类型。
1.八大基本数据类型
java提供了8大基本数据类型:
数据类型 |
长度 |
位数 |
默认值 |
---|---|---|---|
byte |
1Byte |
8 |
0 |
short |
2Byte |
16 |
0 |
int |
4Byte |
32 |
0 |
long |
8Byte |
64 |
0 |
float |
4Byte |
32 |
0.0f |
double |
8Byte |
64 |
0.0d |
boolean |
- |
- |
false |
在一些资料上都有上述介绍。对于其他类型都好理解,唯独对于boolean,长度一直没有很好的说明。我们来看看jvm中是如何实现的。
2.jvm规范描述
首先来看看jvm规范对boolean的描述:
2.3.4 The boolean Type
Although the Java Virtual Machine defines a boolean type, it only provides
very limited support for it. There are no Java Virtual Machine instructions solely
dedicated to operations on boolean values. Instead, expressions in the Java
programming language that operate on boolean values are compiled to use values
of the Java Virtual Machine int data type.
The Java Virtual Machine does directly support boolean arrays. Its newarray
instruction (§newarray) enables creation of boolean arrays. Arrays of type
boolean are accessed and modified using the byte array instructions baload and
bastore (§baload, §bastore).
In Oracle’s Java Virtual Machine implementation, boolean arrays in the Java
programming language are encoded as Java Virtual Machine byte arrays, using 8 bits per
boolean element.
The Java Virtual Machine encodes boolean array components using 1 to represent
true and 0 to represent false. Where Java programming language boolean values
are mapped by compilers to values of Java Virtual Machine type int, the compilers
must use the same encoding.
大意是说,尽管在java虚拟机中定义了boolean类型,但是对它的支持是很有限的。没有专门针对boolean的java虚拟机指令,相反,java语言中操作boolean的表达式,在编译的时候,会被转换为int类型的值。 java虚拟机直接支持boolean数组,newarray指令允许创建boolean数组,使用字节数据的指令baload和bastore访问和修改boolean类型的数组。 在oracle的java虚拟机中,java语言中的boolean数组被编码为java虚拟机中的字节数组。每个boolean元素使用8位,1个字节来表示。 java虚拟机中使用1表示真,0表示假,来对boolean进行编码。如果编译器将java语言的boolean值映射位虚拟机类型的int类型,则编译器也必须使用相同的编码。
通过上述描述可以看出,实际上,boolean的变量是被当作int类型来处理的,而boolean数组,会被特殊处理。
3.java字节码
我们写一段java代码来进行验证:
package com.dhb.test;
import java.nio.ByteBuffer;
public class BooleanTest {
public static void main(String[] args) {
boolean a = false;
boolean[] array = {true,true,true,true,true};
}
}
通过javap来查看其字节码:
$ javap -c -l -s -verbose BooleanTest.class
Classfile /D:/workspace-git/MyProject/target/classes/com/dhb/test/BooleanTest.class
Last modified 2020-9-9; size 477 bytes
MD5 checksum ae4d3635b02ccda5fe262ef944987b72
Compiled from "BooleanTest.java"
public class com.dhb.test.BooleanTest
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#21 // java/lang/Object."<init>":()V
#2 = Class #22 // com/dhb/test/BooleanTest
#3 = Class #23 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 Lcom/dhb/test/BooleanTest;
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 args
#14 = Utf8 [Ljava/lang/String;
#15 = Utf8 a
#16 = Utf8 Z
#17 = Utf8 array
#18 = Utf8 [Z
#19 = Utf8 SourceFile
#20 = Utf8 BooleanTest.java
#21 = NameAndType #4:#5 // "<init>":()V
#22 = Utf8 com/dhb/test/BooleanTest
#23 = Utf8 java/lang/Object
{
public com.dhb.test.BooleanTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 5: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/dhb/test/BooleanTest;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=3, args_size=1
0: iconst_0
1: istore_1
2: iconst_5
3: newarray boolean
5: dup
6: iconst_0
7: iconst_1
8: bastore
9: dup
10: iconst_1
11: iconst_1
12: bastore
13: dup
14: iconst_2
15: iconst_1
16: bastore
17: dup
18: iconst_3
19: iconst_1
20: bastore
21: dup
22: iconst_4
23: iconst_1
24: bastore
25: astore_2
26: return
LineNumberTable:
line 8: 0
line 9: 2
line 10: 26
LocalVariableTable:
Start Length Slot Name Signature
0 27 0 args [Ljava/lang/String;
2 25 1 a Z
26 1 2 array [Z
}
SourceFile: "BooleanTest.java"
可以看到,在定义变量 boolean a = false的时候:
0: iconst_0
1: istore_1
是将int类型的0压入栈顶。之后将int类型的值,存入第一个int类型的变量中去。我们可以对照本地变量表:
LocalVariableTable:
Start Length Slot Name Signature
0 27 0 args [Ljava/lang/String;
2 25 1 a Z
26 1 2 array [Z
slot为1的就是a。那么a=false实际上就是将a=1。 之后再来看对数组的操作:boolean[] array = {true,true,true,true,true};会转换为:
2: iconst_5
3: newarray boolean
5: dup
6: iconst_0
7: iconst_1
8: bastore
9: dup
10: iconst_1
11: iconst_1
12: bastore
13: dup
14: iconst_2
15: iconst_1
16: bastore
17: dup
18: iconst_3
19: iconst_1
20: bastore
21: dup
22: iconst_4
23: iconst_1
24: bastore
25: astore_2
首先是将int 5压入栈顶,之后用这个数字newarray 。之后将iconst_0 和iconst_1 执行bastore。意思就是将数组的第0位将int1设置。之后通过byte数组的方式 bastore到数组中。 实际上可以看出,在字节码中,boolean变量实际上与int等同。而boolean数组的操作,则与操作byte数组等价。
4.代码证明
我们可以用stackOverFlow上的一段代码进行证明,在hotSpot 1.8中,用如下代码证明:
package com.dhb.test;
public class BooleanTest1 {
private static final int SIZE = 1000000;
public static void main(String[] args) {
LotsOfBooleans[] first = new LotsOfBooleans[SIZE];
LotsOfInts[] second = new LotsOfInts[SIZE];
System.gc();
long startMem = getMemory();
for (int i = 0;i < SIZE; i++) {
first[i] = new LotsOfBooleans();
}
System.gc();
long endMem = getMemory();
System.out.println("Size for LotsOfBooleans: " + (endMem - startMem));
System.out.println("Average size: " + ((endMem - startMem) / ((double) SIZE)));
System.gc();
startMem = getMemory();
for (int i=0; i < SIZE; i++)
{
second[i] = new LotsOfInts();
}
System.gc();
endMem = getMemory();
System.out.println("Size for LotsOfInts: " + (endMem - startMem));
System.out.println("Average size: " + ((endMem - startMem) / ((double) SIZE)));
// Make sure nothing gets collected
long total = 0;
for (int i=0; i < SIZE; i++)
{
total += (first[i].a0 ? 1 : 0) + second[i].a0;
}
System.out.println(total);
}
private static long getMemory() {
Runtime runtime = Runtime.getRuntime();
return runtime.totalMemory() - runtime.freeMemory();
}
static class LotsOfBooleans {
boolean a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af;
boolean b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf;
boolean c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf;
boolean d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df;
boolean e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, ea, eb, ec, ed, ee, ef;
}
static class LotsOfInts {
int a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af;
int b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf;
int c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf;
int d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df;
int e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, ea, eb, ec, ed, ee, ef;
}
}
其执行结果:
Size for LotsOfBooleans: 94654104
Average size: 94.654104
Size for LotsOfInts: 336376256
Average size: 336.376256
0
平均每个boolean数组的大小为94Bit,而boolean数组中有80个boolean,那么每个boolean的长度,不可能超过1个Byte。
5.结论
根据以上描述,可以得出结论: boolean在oracle的jvm中,至少在HotSpot 1.8中,boolean变量的长度为4 Byte。而boolean数组中,每个boolean长度为1 Byte。
由于java不同jvm的实现实际上可能会有不同,以上结论仅限于hotSpot 版本。
- 基于SpringBoot的任务管理平台v1.0正式发布
- 大数据系统的Lambda架构
- AKKA中的事件流
- Java初涉感悟
- Android 6.0 Permission权限与安全机制
- SpringBoot工作机制
- Android权限管理PermissionsDispatcher2.3.2使用+原生6.0权限使用
- SpringBoot中的IoC
- Sonar安装配置
- 《AngularJS深度剖析与最佳实践》推荐序
- JavaScript递归方法 生成 json tree 树形结构数据
- springboot使用hibernate validator校验
- 机器学习(三) ——k-近邻算法基础
- SpringBoot实战 之 异常处理篇
- 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 文档注释
- How does InnoDB behave without a Primary Key(11.InnoDB在没用主键情况下的行为)
- 输入示例,自动生成代码:TensorFlow官方工具TF-Coder已开源
- 聊聊java8中的@sun.misc.Contended与伪共享
- InnoDB Tidbit:The doublewrite buffer wastes 32 pages (512 KiB) (12.双写缓冲区会导致512KB的浪费)
- 10 | Tornado源码分析:Gen 对象(上)
- springboot使用spring-cloud-starter-alibaba-sentinel导致响应变成xml格式
- 内网安全攻防之内网渗透测试基础
- CMake脚本中如何修改XCode工程属性?
- 数值微分|有限差分法的误差分析
- Odyssey
- 【MySQL】之join算法详解
- 性能最佳实践:查询模式和分析
- Node 如何在 Controller 层进行数据校验
- FlutterDojo设计之道——状态管理之路(二)
- EyouCms前台GetShell漏洞复现