面试题答案
一键面试Java基本数据类型在内存中的存储方式
- 整数类型:
- byte:8位有符号整数,在内存中占1个字节。按补码形式存储,最高位为符号位,0表示正数,1表示负数。例如,5的二进制表示为
00000101
, -5的补码为11111011
。 - short:16位有符号整数,占2个字节。同样按补码存储,原理与byte类似。
- int:32位有符号整数,占4个字节。按补码存储。例如,10的二进制表示为
00000000 00000000 00000000 00001010
。 - long:64位有符号整数,占8个字节。按补码存储。
- byte:8位有符号整数,在内存中占1个字节。按补码形式存储,最高位为符号位,0表示正数,1表示负数。例如,5的二进制表示为
- 浮点类型:
- float:32位单精度浮点数,占4个字节。遵循IEEE 754标准,分为符号位(1位)、指数位(8位)和尾数位(23位)。例如,
1.5
的二进制表示为0 01111111 10000000000000000000000
。 - double:64位双精度浮点数,占8个字节。同样遵循IEEE 754标准,符号位(1位)、指数位(11位)和尾数位(52位)。
- float:32位单精度浮点数,占4个字节。遵循IEEE 754标准,分为符号位(1位)、指数位(8位)和尾数位(23位)。例如,
- 字符类型:
- char:16位无符号整数,占2个字节。用于表示Unicode字符,存储的是字符的Unicode码点。例如,字符
'A'
的Unicode码点是65,二进制表示为00000000 01000001
。
- char:16位无符号整数,占2个字节。用于表示Unicode字符,存储的是字符的Unicode码点。例如,字符
- 布尔类型:
- boolean:理论上占1位,但实际实现中通常占1个字节。值只有
true
和false
。在JVM中并没有明确规定其存储方式,不同JVM实现可能不同。
- boolean:理论上占1位,但实际实现中通常占1个字节。值只有
自动装箱和拆箱原理(以Integer包装类为例)
- 自动装箱:将基本数据类型转换为对应的包装类对象。例如,
int
转换为Integer
。在Java 5.0引入自动装箱后,以下代码是合法的:
int num = 10;
Integer integerObj = num; // 自动装箱
实际上,编译器会将上述代码转换为:
int num = 10;
Integer integerObj = Integer.valueOf(num);
Integer.valueOf(int)
方法会先检查值是否在IntegerCache
缓存范围内(-128到127),如果在则直接返回缓存中的对象,否则创建一个新的Integer
对象。
- 自动拆箱:将包装类对象转换为基本数据类型。例如,
Integer
转换为int
。如下代码:
Integer integerObj = new Integer(10);
int num = integerObj; // 自动拆箱
编译器会将其转换为:
Integer integerObj = new Integer(10);
int num = integerObj.intValue();
实际应用中可能遇到的问题
- 空指针异常:在自动拆箱时,如果包装类对象为
null
,会抛出NullPointerException
。例如:
Integer integerObj = null;
int num = integerObj; // 这里会抛出NullPointerException
- 性能问题:频繁的自动装箱和拆箱操作会产生额外的对象创建和销毁,影响性能。例如在循环中进行装箱和拆箱操作,应尽量避免。
- 缓存问题:由于
Integer
的valueOf
方法使用了缓存,在比较两个Integer
对象时,如果值在缓存范围内,直接使用==
比较会返回true
,否则返回false
。而使用equals
方法则是比较对象的值。例如:
Integer a = 100; // 自动装箱,100在缓存范围内
Integer b = 100;
System.out.println(a == b); // 输出true
Integer c = 200; // 自动装箱,200不在缓存范围内
Integer d = 200;
System.out.println(c == d); // 输出false
System.out.println(c.equals(d)); // 输出true