基础很重要, 基础很重要, 基础很重要. 重要的事情说三遍,.
今天聊一聊 Java 的数据比较, 这个范围比较大, 基础类型的比较, 引用类型的比较.
前提:
1,Java 和 c# 都提供自动装箱和自动拆箱操作, 何为自动装箱, 简单点说就是将值类型转换成为引用类型, 自动拆箱就是将引用类型转换成为值类型. 并且我们还经常被教导, 要避免自动的装箱和拆箱操作, 因为这个会影响性能.
2, 比较常用的运算符是 ==,equals.
下面分几类来说明数据的比较,
引用类型之间的比较: Integer 与 Integer 之间的比较, Boolean 与 Boolean 之间的比较, Integer 与 Boolean 之间的比较
值类型之间的比较: int 与 int 之间的比较, int 与 bool 之间的比较
值类型与引用类型之间的比较: Integer 与 int 之间的比较, Boolean 与 bool 之间的比较
开工
引用类型之间的比较 --Integer 与 Integer 之间的比较
简单说明一下, Integer 是引用类型, 代表的是整形数字
上代码
- public static void main(String[] args) throws Exception {
- Integer integer = new Integer(0);
- Integer mInteger = Integer.valueOf(0);
- Integer sInteger = 0;
- System.out.println(integer == mInteger);//false
- System.out.println(integer == sInteger);//false
- System.out.println(mInteger == sInteger);//true
- System.out.println(memoryAddress(integer));
- System.out.println(memoryAddress(mInteger));
- System.out.println(memoryAddress(sInteger));
- }
- private static int memoryAddress(Object object) {
- // 内存地址会有所不同
- return System.identityHashCode(object);
- }
执行结果:
分析:
1, 执行结果和我们预想的不太一样, 引用类型是在堆上存放的, 每个引用的地址应该都不相同. 但是 mInteger == sInteger 执行结果为 true, 并且 mInteger ,sInteger 的内存地址是相同的.
2, 要分析这个原因, 我们需要了解 Java 设计者为了性能而进行的一些努力, 查看 Java 源代码, 可以看到 Integer 的 valueof 方法里面包含了一个缓存: 其中 IntegerCache.low =-127,IntegerCache.high=128
- @HotSpotIntrinsicCandidate
- public static Integer valueOf(int i) {
- if (i>= IntegerCache.low && i <= IntegerCache.high)
- return IntegerCache.cache[i + (-IntegerCache.low)];
- return new Integer(i);
- }
对于使用 Integer.valueof() 方法, 如果数值是 - 127 至 128, 那么会使用缓存对象, 否则会 new 一个对象.
3,Integer sInteger = 0; 发生了什么呢? 自动装箱, 等价于 Integer sInteger=Integer.valueOf(0). 通过这个, 我们就可以得出比较等于 true 的原因了, 都是从缓存中读取的对象, 难怪内存地址会一致.
引用类型比较 --Integer 与 Integer 引用类型比较 使用 equals
上代码:
- public static void main(String[] args) throws Exception {
- Integer integer = new Integer(0);
- Integer mInteger = Integer.valueOf(0);
- Integer sInteger = 0;
- System.out.println(integer == mInteger);// false
- System.out.println(integer == sInteger);// false
- System.out.println(mInteger == sInteger);// true
- System.out.println(memoryAddress(integer));
- System.out.println(memoryAddress(mInteger));
- System.out.println(memoryAddress(sInteger));
- System.out.println(integer.equals(mInteger));//true
- System.out.println(integer.equals(sInteger));//true
- System.out.println(mInteger.equals(sInteger));//true
- }
- private static int memoryAddress(Object object) {
- // 内存地址会有所不同
- return System.identityHashCode(object);
- }
分析: 使用 equals 比较, 只要数值相同, 那么比较结果就是相同. 查看 Java 源代码:
- public boolean equals(Object obj) {
- if (obj instanceof Integer) {
- return value == ((Integer)obj).intValue();
- }
- return false;
- }
可以看到 Integer 的 equals 比较, 其实比较的就是数值.
值类型之间的比较: int 与 int
上代码
- int m=0;
- int i=0;
- int s=0;
- System.out.println(m==i);//true
- // 值类型是没有 equals 方法
- //System.out.println(m.equals(i));
分析: 对于 int 的比较, 无需多言, 本来就是数值比较.
Integer 与 int 的比较:
- Integer integer = new Integer(0);
- Integer mInteger = Integer.valueOf(0);
- Integer sInteger = 0;// 等价于 Integer.valueof
- int i = 0;
- System.out.println(integer == i);//true
- System.out.println(mInteger == i);//true
- System.out.println(sInteger == i);//true
- System.out.println(integer.equals(i));//true
- System.out.println(mInteger.equals(i));//true
- System.out.println(sInteger.equals(i));//true
分析:
1,Integer 类型与 int 类型通过 == 比较, Integer 会自动拆箱, 转换成 int 数值进行比较
2,equals 方法更是读取对应的 int 数值进行比较.
因此引用类型与值类型之间的比较, 使用 equals 与 == 都可以.
简单总结:
1, 引用类型之间的比较, 由于存在 - 127 至 128 之间的缓存对象, 因此使用 == 进行比较存在风险. 优先使用 equals 进行比较
2, 引用类型与值类型进行比较, 由于会自动拆箱, 因此使用 == 和 equals 都可以正确得到结果
3, 建议在实际编码过程中, 对数值的比较使用 equals
深入总结:
不仅仅 Integer, 其他的基本类型也都存在缓存, 下面给出一个简单图表进行说明
基本类型 | 装箱类型 | 取值范围 | 是否缓存 | 缓存范围 |
byte | Byte | -128~127 | 是 | -128~127 |
short | Short | -2^15 ~ (2^15 - 1) | 是 | -128~127 |
int | Integer | -2^31 ~ (2^31 - 1) | 是 | -128~127 |
| Long | -2^63 ~ (2^63 - 1) | 是 | -128~127 |
float | Float | -- | 否 | |
double | Double |
| 否 | |
boolean | Boolean | true、false | 是 | true、false |
char | Character | \u0000 ~ \uffff | 是 | \u0000 ~ \uffff |
Java 博大精深, 要想深入, 基础必须要好, 才能避免 bug.
我们程序员的职责就是少写 bug, 这才是我们一直学习的动力.
来源: https://www.cnblogs.com/jiagoushi/p/9943637.html