关于Integer数值比较的问题以及不可变对象
2017-01-19 11:01
302 查看
前言
写这篇文章是因为在之前的项目中通过findbugs进行代码优化,爆出的问题。其实我们的代码中暗藏危机,只是没有暴露出来而已我这里使用jdk7
测试
public static void main(String[] args) { Integer a = 10; Integer b = 10; System.out.println("a == b " + (a == b)); System.out.println("a.equals(b) " + (a.equals(b))); System.out.println("a.intValue() == b.intValue() " + (a.intValue() == b.intValue())); System.out.println("a.compareTo(b) " + (a.compareTo(b))); System.out.println("---------"); a = new Integer(10); b = new Integer(10); System.out.println("a == b " + (a == b)); System.out.println("a.equals(b) " + (a.equals(b))); System.out.println("a.intValue() == b.intValue() " + (a.intValue() == b.intValue())); System.out.println("a.compareTo(b) " + (a.compareTo(b))); System.out.println("---------"); a = 189; b = 189; System.out.println("a == b " + (a == b)); System.out.println("a.equals(b) " + (a.equals(b))); System.out.println("a.intValue() == b.intValue() " + (a.intValue() == b.intValue())); System.out.println("a.compareTo(b) " + (a.compareTo(b))); System.out.println("---------"); int m = 189; int n = 189; System.out.println(m == n); }
运行结果
a == b true a.equals(b) true a.intValue() == b.intValue() true a.compareTo(b) 0 --------- a == b false a.equals(b) true a.intValue() == b.intValue() true a.compareTo(b) 0 --------- a == b false a.equals(b) true a.intValue() == b.intValue() true a.compareTo(b) 0 --------- true
奇不奇怪,为什么会酱紫呢?
原因分析
我们都知道,在java中==是比较的两个对象所指向的内存地址是否相等,而
equals方法比较的是值。如果按照这个理论,上面的结果中可以看出
Integer a = 10;Integer b = 10;这两个对象内存地址是同一个,也就是a和b两个引用指向同一个对象。而
Integer a = 189;Integer b = 189;中,a和b两个引用指向了两个不同的对象。真的是这样吗?为什么呢?
我们查看
Integer的源码:
/** * Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. The size of the cache * may be controlled by the -XX:AutoBoxCacheMax=<size> option. * During VM initialization, java.lang.Integer.IntegerCache.high property * may be set and saved in the private system properties in the * sun.misc.VM class. */ private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} } /** * 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) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } /** * The value of the {@code Integer}. * * @serial */ private final int value; /** * Constructs a newly allocated {@code Integer} object that * represents the specified {@code int} value. * * @param value the value to be represented by the * {@code Integer} object. */ public Integer(int value) { this.value = value; }
通过这段源码可知:
- Integer是不可变对象,因为里面的value是final的
private final int value;
- -128到127之间的数据放到了
IntegerCache中,
IntegerCache是
static的,因此将会放到常量池中作为缓存使用
因此可知,
Integer a = 10;Integer b = 10;这两个对象其实是从
IntegerCache缓存中取的,是同一个对象,地址肯定是相同的。而
Integer a = 189;Integer b = 189;是创建的两个新的对象,因此地址肯定不同啦
结论
永远不要用==比较integer对象,以避免一些偶发不可预测的错误。
其他与此相关的知识点
Object
与Integer
比较
Object o1 = 10; Integer o2 = 10; System.out.println(o1 == o2); Object o3 = 200; Integer o4 = 200; System.out.println(o3 == o4);
结果:
true false
原因与上面的一样。
* jdk8中上面代码编译可是不通过的吆*
锁相关
我们都知道用于加锁的对象必须是不可变对象, 永远不要再不可变对象上加锁因此永远不要再
integer对象上加锁,因为其实不可变对象
private final int value;。当integer重新赋值或者进行了计算以后,得到的值是新创建的对象。
class Stu{ private int a; public int getA() { return a; } public void setA(int a) { this.a = a; } } public class Test { public static void main(String[] args) { Stu stu = new Stu(); stu.setA(1); increase(stu); increase(stu); System.out.println(stu.getA()); System.out.println("---"); Integer a = 1; increase(a); increase(a); System.out.println(a); } //我们知道java方法传递对象是传引用的 public static void increase(Stu stu){ stu.setA(stu.getA() + 1); System.out.println(stu.getA()); } public static void increase(Integer integer){ integer = integer + 1; System.out.println(integer);//这个integer其实是新创建的一个对象,而不是参数传入进来的对象 } }
结果
2 3 3 --- 2 2 1
相关文章推荐
- 关于Integer对象比较,和int基本类型比较的一些问题
- 面试也常遇到的关于Integer大小比较的问题
- 关于WCF,DataService中,查找模型对象时,主键含有数值时找不到对象问题处理
- Integer对象用== 和equals比较大小的问题
- java-数值,对象比较---"=="和"equals"以及自动装箱后的比较
- 关于FreeMarker获取一个对象中另一个对象出现的问题以及解决方法
- 关于指针比较(涉及的是对象同一性的问题)
- “好程序员笔记”关于对象的比较以及一个二叉树的实现
- 关于Integer大小比较的问题
- 关于ajax对象一些常用属性、事件和方法大小写比较常见的问题总结
- 关于Integer数值大于127时使用等号比较时的坑
- 【转】关于Integer大小比较的问题
- 关于输出null对象,以及try/catch/finally比较好玩的一段代码
- 关于Integer的比较大小问题即到底是用“==”还是“equals”来比较大小
- 关于Integer大小比较的问题
- 关于new、Create、对象以及窗口的一点问题
- 关于Integer大小比较的问题
- 关于直接比较两个对象是否相等或则说List集合里是否包含某个对象的问题
- Integer数值比较问题
- 关于Integer与int之间比较的问题