1. 前言
我写这篇文章的目的是什么呢?
不在于给出例子的结果,即‘判断基础类型包装类是否相等的结果’。
基于这些问题和结果,我会结合代码原理、栈原理等,讲述结果背后的原理。
java有几种基础数据类型呢?干java这行的,大部分人都知道是8种。
jdk中对它们分别提供了包装类。以下比较相等问题,仅针对包装类进行讨论。
2. 给出问题
基于下面的代码,读者可以先给出自己的结果。
public static void main(String[] args) {
Integer i =-128;
Integer j = -128;
System.out.println(i == j);
i =127;
j = 127;
System.out.println(i == j);
i =128;
j = 128;
System.out.println(i == j);
test(1);
test(128);
}
public static void test(int i){
System.out.println("================================");
Integer i1 = new Integer(i);
Integer i2 = new Integer(i);
System.out.println("i1 == i2 : " + (i1 == i2));
System.out.println("i1.equals(i2) : " + (i1.equals(i2)));
System.out.println("new Integer(i) == new Integer(i) : " + (new Integer(i) == new Integer(i)));
System.out.println("Integer.valueOf(i) == Integer.valueOf(i) : " + (Integer.valueOf(i) == Integer.valueOf(i)));
Integer i3 = Integer.valueOf(i);
Integer i4 = Integer.valueOf(i);
System.out.println("i3 == i4 : " + (i3 == i4));
}
3. 讲述原理
3.1. new关键字
简述为:触发类加载,为类实例分配内存空间,给出内存空间地址。
3.2. 包装类
3.2.1. 提供包装类型的原因
- 便于String与基础类型之间互相转换
- 提供其他有用处的方法
3.2.2. cache部分实例
总述
- 出于时间和空间考虑,部分包装类会缓存一部分数据,但是缓存只是很小一部分数据,一旦超出范围就用new喽。
cache部分数据的原因
- 节省空间和时间
cache使用场景
- 自动装箱时,无须重复new 对象
- 用于valueof
如果你还没有看过valueOf源码的话,可以看看下边的注释。
/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
哪些包装类
- Byte
- Short
- Character
- Integer
- Long
cache数据范围
Byte | 256(-128 -- 127) |
Character | 128(0 -- 127) |
Short | 256(-128 -- 127) |
Integer | 默认256(-128 -- 127) |
Long | 256(-128 -- 127) |
超过范围怎么办
- new新对象
3.3. 栈帧的内容
请查看另一篇讲述java内存模型的文章 你可以了解到jvm执行指令时是如何获取数据的。
3.3.1. ==比较什么
在栈帧部分,已经知道本地变量数组和操作数栈了。那么==的处理过程就是操作数栈弹出的两个数据进行比较。例如引用的实例内存空间地址。
3.3.2. equals做了什么
不考虑float double,其他6中包装类型的equals方法内部均是比较其对应基础类型的数据。
public int compareTo(Byte anotherByte) {
return compare(this.value, anotherByte.value);
}
public boolean equals(Object obj) {
if (obj instanceof Byte) {
return value == ((Byte)obj).byteValue();
}
return false;
}
4. 输出结果
true
true
false
================================
i1 == i2 : false
i1.equals(i2) : true
new Integer(i) == new Integer(i) : false
Integer.valueOf(i) == Integer.valueOf(i) : true
i3 == i4 : true
================================
i1 == i2 : false
i1.equals(i2) : true
new Integer(i) == new Integer(i) : false
Integer.valueOf(i) == Integer.valueOf(i) : false
i3 == i4 : false