Nul*_*ion 25 java autoboxing equality
我知道这个主题有类似的帖子,但它们并没有完全解决我的问题.当你这样做时:
Integer a = 10;
Integer b = 10;
System.out.println("a == b: " + (a == b));
Run Code Online (Sandbox Code Playgroud)
这将(显然)打印true大部分时间,因为[-128,127]范围内的整数以某种方式被缓存.但:
Integer a = new Integer(10);
Integer b = new Integer(10);
System.out.println("a == b: " + (a == b));
Run Code Online (Sandbox Code Playgroud)
会回来false.我理解我要求整数的新实例,但由于盒装原语在Java中是不可变的,并且机器已经在那里做"正确的事情"(如第一种情况所示),为什么会发生这种情况?
如果具有10的Integer的所有实例在内存中都是相同的对象,那会不会更有意义?换句话说,为什么我们没有"Integer interning",这类似于"String interning"?
更好的是,如果表示同一事物的盒装基元的实例(无论值(和类型)是否是同一个对象),它会更有意义吗?或者至少正确回答==?
nec*_*cer 19
应该非常清楚的是,缓存具有不可接受的性能损失 - 每次创建Integer时都会进行额外的if语句和内存查找.仅此一点就掩盖了任何其他原因以及其他原因令人痛苦.
至于"正确"回答==,OP在他的正确性假设中是错误的.整数DO通过一般Java社区对正确性的期望来正确地响应==,当然还有规范对正确性的定义.也就是说,如果两个引用指向同一个对象,则它们是==.如果两个引用指向不同的对象,即使它们具有相同的内容也不会 ==.因此,new Integer(5) == new Integer(5)评估时应该不足为奇false.
更有趣的问题是为什么 new Object();每次都需要创建一个唯一的实例?即为什么new Object();不允许缓存?答案是wait(...)和notify(...)电话.缓存new Object()s会不正确地导致线程彼此同步.
如果不是这样,那么Java实现可以new Object()用单例完全缓存s.
这应该解释为什么new Integer(5)必须完成7次才能创建7个唯一Integer对象,每个对象包含值5(因为Integer扩展Object).
次要的,不太重要的东西:这个不错的方案中的一个问题是自动装箱和自动装箱功能.如果没有这个功能,你就无法进行比较new Integer(5) == 5.为了实现这些,爪哇unboxes对象(和它没有框的原语).因此new Integer(5) == 5转换为:( new Integer(5).intValue() == 5而不是 new Integer(5) == new Integer(5).
最后一两件事要明白的是,自动装箱的n是不被做new Integer(n).它是通过调用内部完成的Integer.valueOf(n).
如果您认为自己理解并希望自己测试,请预测以下程序的输出:
public class Foo {
public static void main (String[] args) {
System.out.println(Integer.valueOf(5000) == Integer.valueOf(5000));
System.out.println(Integer.valueOf(5000) == new Integer(5000));
System.out.println(Integer.valueOf(5000) == 5000);
System.out.println(new Integer(5000) == Integer.valueOf(5000));
System.out.println(new Integer(5000) == new Integer(5000));
System.out.println(new Integer(5000) == 5000);
System.out.println(5000 == Integer.valueOf(5000));
System.out.println(5000 == new Integer(5000));
System.out.println(5000 == 5000);
System.out.println("=====");
System.out.println(Integer.valueOf(5) == Integer.valueOf(5));
System.out.println(Integer.valueOf(5) == new Integer(5));
System.out.println(Integer.valueOf(5) == 5);
System.out.println(new Integer(5) == Integer.valueOf(5));
System.out.println(new Integer(5) == new Integer(5));
System.out.println(new Integer(5) == 5);
System.out.println(5 == Integer.valueOf(5));
System.out.println(5 == new Integer(5));
System.out.println(5 == 5);
System.out.println("=====");
test(5000, 5000);
test(5, 5);
}
public static void test (Integer a, Integer b) {
System.out.println(a == b);
}
}
Run Code Online (Sandbox Code Playgroud)
对于额外的功劳,如果所有内容==都更改为,也会预测输出.equals(...)
更新:感谢用户@sactiw的评论:"默认的缓存范围是-128到127和java 1.6以后你可以通过传递-XX重置上限值> = 127:AutoBoxCacheMax = from command line"
这可能会破坏在此设计更改之前编写的代码,当时每个人都认为两个新创建的实例是不同的实例.它可以用于自动装箱,因为之前不存在自动装箱,但改变新装置的含义太危险了,可能不会带来太大的好处.短期对象的成本在Java中并不大,甚至可能低于维护长寿命对象缓存的成本.
如果您检查来源,您会看到:
/**
* Returns an Integer instance representing the specified int value. If a new
* Integer instance is not required, this method should generally be used in
* preference to the constructor Integer(int), as this method is likely to
* yield significantly better space and time performance by caching frequently
* requested values.
*
* @Parameters: i an int value.
* @Returns: an Integer instance representing i.
* @Since: 1.5
*/
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
Run Code Online (Sandbox Code Playgroud)
来源:链接
这就是为什么==用整数返回布尔值 true的性能原因——这完全是一个黑客。如果你想比较值,那么你有compareto或equals方法。
在其他语言中,比如也可以==用来比较字符串,基本相同的道理,被称为java语言最大的硬伤之一。
int是一种原始类型,由语言预定义并由保留关键字命名。作为原语,它不包含类或任何与类相关的信息。Integer是一个不可变的原始类,它通过包私有的本地机制加载并转换为 Class - 这提供了自动装箱并在 JDK1.5 中引入。之前的 JDK1.5int和Integerwhere 2 非常不同的东西。
| 归档时间: |
|
| 查看次数: |
6167 次 |
| 最近记录: |