8种基本类型对应的包装类
Java有两套类型系统:基本类型(放在栈上,快)和引用类型(放在堆上,功能多)
包装类就是给基本类型穿了件衣服,让它们变成对象,能参加”对象世界”的活动
| 基本类型 |
包装类 |
内存大小 |
默认值 |
byte |
Byte |
1字节 |
0 |
short |
Short |
2字节 |
0 |
int |
Integer |
4字节 |
0 |
long |
Long |
8字节 |
0L |
float |
Float |
4字节 |
0.0f |
double |
Double |
8字节 |
0.0 |
char |
Character |
2字节 |
‘\u0000’ |
boolean |
Boolean |
不确定 |
false |
注意:int 对应 Integer(不是Int),char 对应 Character(不是Char),这两个名字不一样
为什么需要包装类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Test public void testWhyWrapper() {
List<Integer> list = new ArrayList<>();
list.add(1); list.add(2); list.add(3);
Integer score = null;
int num = Integer.parseInt("123"); String str = Integer.toString(456); int max = Integer.MAX_VALUE; String binary = Integer.toBinaryString(10); System.out.println("parseInt: " + num); System.out.println("MAX_VALUE: " + max); System.out.println("toBinaryString: " + binary); }
|
自动装箱和自动拆箱
装箱就是基本类型穿上对象的外衣,拆箱就是脱掉外衣变回基本类型
Java 5 以后自动帮你做,不用手动转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Test public void testAutoBoxing() {
Integer a = 100;
int b = a;
Integer x = 10; Integer y = 20; int sum = x + y; System.out.println("sum = " + sum);
Double d = 3.14; double dd = d;
List<Integer> list = new ArrayList<>(); list.add(42); int val = list.get(0); }
|
⚠️ 陷阱1:Integer缓存
这是面试超高频考点,必须搞懂
Java对 -128~127 范围内的Integer做了缓存,这个范围内 == 比较是true,超出范围就是false
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Test public void testIntegerCache() {
Integer a = 127; Integer b = 127; System.out.println(a == b); System.out.println(a.equals(b));
Integer c = 128; Integer d = 128; System.out.println(c == d); System.out.println(c.equals(d));
Integer e = -128; Integer f = -128; System.out.println(e == f);
Integer g = -129; Integer h = -129; System.out.println(g == h); }
|
原理:Integer.valueOf() 内部有个缓存数组,-128到127的Integer对象预先创建好了
铁律:包装类比较永远用 .equals(),别用 ==
参考 运算符 中关系运算符和 String类与字符串操作 中的 == vs equals
⚠️ 陷阱2:拆箱遇到null
当一个包装类对象是null,自动拆箱时会直接炸掉(NullPointerException)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Test public void testNullUnboxing() {
Integer num = null;
List<Integer> list = new ArrayList<>(); list.add(null);
boolean flag = true; Integer i = null;
Integer score = null; int safeScore = (score != null) ? score : 0; System.out.println("安全的分数:" + safeScore); }
|
防御建议
从数据库、接口拿到的包装类,用之前先判null
或者用 Optional(Java 8+)来处理
常用转换方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @Test public void testConversion() {
int a = Integer.parseInt("123"); System.out.println(a + 1);
double b = Double.parseDouble("3.14"); System.out.println(b);
String s1 = String.valueOf(42); String s2 = Integer.toString(42); String s3 = 42 + ""; System.out.println(s1);
try { int bad = Integer.parseInt("abc"); } catch (NumberFormatException e) { System.out.println("不是数字:" + e.getMessage()); }
try { int bad = Integer.parseInt("3.14"); } catch (NumberFormatException e) { System.out.println("整数解析不了小数:" + e.getMessage()); } }
|
| 转换方向 |
方法 |
示例 |
| String → int |
Integer.parseInt("123") |
123 |
| String → double |
Double.parseDouble("3.14") |
3.14 |
| String → boolean |
Boolean.parseBoolean("true") |
true |
| int → String |
String.valueOf(42) |
“42” |
| int → String |
Integer.toString(42) |
“42” |
| int → Integer |
Integer.valueOf(42) |
Integer对象 |
常见坑总结
| 坑 |
说明 |
怎么避免 |
== 比较Integer |
-128~127是true,其他是false |
永远用 .equals() |
| null拆箱NPE |
Integer num = null; int n = num; 会炸 |
用之前先判null |
| parseInt非数字 |
Integer.parseInt("abc") 抛异常 |
try-catch或先校验 |
| 性能浪费 |
频繁装箱拆箱有开销 |
能用基本类型就别用包装类 |
| 三元运算符拆箱 |
flag ? integerObj : 0 可能NPE |
保持两边类型一致 |
练习题
题1:预测输出结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Test public void testPredictOutput() { Integer a = 100; Integer b = 100; Integer c = 200; Integer d = 200;
System.out.println(a == b); System.out.println(c == d); System.out.println(a.equals(b)); System.out.println(c.equals(d)); }
|
题2:找出下面代码的Bug
1 2 3 4 5 6 7 8 9 10 11 12
| @Test public void testFindBug() {
Map<String, Integer> map = new HashMap<>(); map.put("score", null);
Integer score = map.get("score"); int safeScore = (score != null) ? score : 0; System.out.println("分数:" + safeScore); }
|
题3:比较以下两种写法的区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Test public void testCompare() {
long start1 = System.currentTimeMillis(); long sum1 = 0L; for (int i = 0; i < 10000000; i++) { sum1 += i; } System.out.println("基本类型耗时:" + (System.currentTimeMillis() - start1) + "ms");
long start2 = System.currentTimeMillis(); Long sum2 = 0L; for (int i = 0; i < 10000000; i++) { sum2 += i; } System.out.println("包装类耗时:" + (System.currentTimeMillis() - start2) + "ms");
}
|