1. java 数据类型?
1.1 java中8大基本类型?
- 整型 byte;
- 整型 short;
- 整型 int;
- 整型 long;
- 浮点型 float;
- 双精度浮点型 double;
- 布尔型 boolean;
- 字符型 char;
1.2 java数据类型分类
- 基本数据类型(8大基本数据类型);
- 引用类型;
引用类型具体划分为:
接口 Interface;
类 Class;
枚举 Enum;
数组 Array;
注解 Annotation;
2. java 包装类?
2.1 什么是java中的包装类?
- java中存在8大基本数据类型,这8种基本数据类型本身存储的是值,并不是引用地址。
- 为了实现“处处皆对象”的理念,java对8大基本数据类型分别创造了对应的包装类。
byte – Byte
short – Short
int – Integer
long – Long
float – Float
double – Double
boolean – Boolean
char – Character
2.2 自动装箱和自动拆箱?
- jdk 5之前,不存在自动装箱和自动拆箱。说白了就是基本数据类型和对应的包装类型进行转换,需要手动转换。比如:
int a = 10; // 手动将a装箱为Integer类型 Integer b = new Integer(a); // 同上,手动装箱 Integer c = Integer.valueOf(a); // 将c手动拆箱转换为int类型 int d = c.intValue();
其他基本类型和包装类型的手动装箱、手动拆箱与Integer类似。
- jdk5之后,JVM提供了自动装箱和拆箱:
// 将int类型的10自动装箱为Integer类型 Integer b = 10; // 将Integer类型的b自动拆箱为int类型 int c = b;
- 自动装箱和拆箱实际上就是对valueOf()方法和intValue()方法的默认调用。由此可见,当拆箱对象为null值时,自动拆箱相当于如下:
Integer a = null; // a自动拆箱,相当于调用 a.intValue(),因此会报空指针异常。 int b = a;
2.3 包装类进行==比较的陷阱
以Integer为例,Integer实际上在比较时,两个Integer对象进行 == 比较,当Integer类型数据再 -128-127 之间时,会直接返回Integer内部的固定引用(Integer对象有个私有静态内部类IntegerCache,将 -128-127之间的数据提前实例化好缓存起来了)。因此当比较数据再该范围时,两个数值相同的Integer对象使用 == 比较的结果为true。
然而,一旦数值不在该范围,使用==比较的则是两个重新创建的Integer实例,因此即便数值相同,== 的比较结果也为false。
总结:
- 如果Integer的两个数在-128-127之间,则直接使用==比较相等(必要时进行判空)。
- 比较两个Integer数值,可以使用Integer内部的equals()方法(必要时进行判空),或者直接使用Objects.equals()方法进行比较,或者将两个对象分别通过intValue()方法拆箱为基本类型后再使用==进行比较。
2.4 建议使用Objects.equals进行比较两个值
当我们比较两个 Integer
类型的对象时,Objects.equals
源码确实会首先使用 ==
运算符来比较。这时候,如果 Integer
的值超出了缓存范围(-128
到 127
),==
比较的是两个对象的内存地址,而不是值,可能会导致比较结果为 false
。
然而,深入分析 Objects.equals
的逻辑可以澄清这个问题:
Objects.equals
的完整逻辑
Objects.equals(a, b)
首先检查a == b
:- 如果
a
和b
是同一个对象(即内存地址相同),返回true
。 - 如果地址不同,则继续比较。
- 如果
- 如果
a
为null
,直接返回false
(因为此时b
一定不为null
)。 - 调用
a.equals(b)
,进入Integer.equals
方法:Integer.equals
方法比较的是值,即value == ((Integer) obj).intValue()
。
因此,即使 a
和 b
的地址不同,只要它们的值相等,最终结果仍然是 true
。
验证示例
Integer a = 200; // 超出缓存范围
Integer b = 200; // 超出缓存范围
System.out.println(a == b); // false,因为地址不同
System.out.println(Objects.equals(a, b)); // true,因为最终调用了 equals
在这段代码中:
a == b
返回false
,因为两个对象是不同的实例。Objects.equals(a, b)
返回true
,因为值相等。
关键点:为何 Objects.equals
安全?
- 即使
==
比较不通过,Objects.equals
的逻辑会继续调用a.equals(b)
来比较值。 Integer.equals
方法会比较实际的数值,而不是引用。
总结
虽然 Objects.equals
确实会先进行 ==
比较,但如果两个 Integer
对象的地址不同,Objects.equals
仍会调用 equals
方法来比较它们的值。因此,在使用 Objects.equals
时,无需担心缓存范围问题,它始终能够正确比较 Integer
的值是否相等。
文档信息
- 本文作者:Marshall