10

在我的笔记中找到以下内容,但我无法理解:

原始类型包装类为有限数量的值实现缓存。
这保证了有限数量的深度相等的包装对象也是浅相等的: If o1.equals( o2 )then o1 == o2
例如,new Integer( 0 ) == new Integer( 0 )
一般来说,这并不总是有效。
例如,new Integer(666) == new Integer(666)
可能不成立。
缓存的原因是它可以节省内存。
一般来说,缓存适用于“小”原始值。

我不明白这是什么意思,或者深(.equals())和浅(==)等于之间有什么区别。我知道在实践中, .equals 必须用于对象, == 用于 Integral 值,但对此的实际推理暗示了我。

我假设浅的名称可能只是检查两个值的类型和名称是否相同,而深层检查两个变量是否指向同一个对象?不过,我看不出缓存将如何在这里发挥作用,或者为什么它会有用。

4

5 回答 5

9

当你这样做时,==你正在比较引用是否相等。这意味着您是在说“两个对象的内存地址是否相同?”

当你这样做时,.equals()你正在比较对象本身是否相等。这意味着您是在说“这两个对象是否认为自己相等?”

给出的例子很糟糕。JLS 要求对这些数字进行的唯一缓存是.valueOf()方法。构造函数没有被缓存。

此外,JLS 仅指定您必须缓存的最小值[-128:127]。如果他们愿意,JVM 实现可能会缓存更多。这意味着Integer.valueOf(500) == Integer.valueOf(500)可能false在某些机器上,但true在其他机器上。

class biziclop {

    public static void main(String[] args) {
        System.out.println(new Integer(5) == new Integer(5));
        System.out.println(new Integer(500) == new Integer(500));

        System.out.println(Integer.valueOf(5) == Integer.valueOf(5));
        System.out.println(Integer.valueOf(500) == Integer.valueOf(500));
    }
}

结果是:

C:\Documents and Settings\glow\My Documents>java biziclop
false
false
true
false

C:\Documents and Settings\glow\My Documents>

在此处查看更详细的答案(评论是宝石!):为什么人们仍然在 Java 中使用原始类型?

于 2011-04-18T13:30:45.730 回答
8

Well, actually shallow/deep dissection is different from ==/equal dissection:

  1. == compares for object identity, that is you checking whether operands are the same in fact (two references to the same area of memory), whereas equals compares for object equivalence, that is "logical" value of two, possibly not identical objects, is the same. If for two objects

    a == b
    

    then it's true that

    a.equals(b) // if a != null
    

    , but opposite isn't true in all cases.

  2. shallow/deep distinction makes sense only for equals comparison. Shallow means that you compare only immediate contents of two objects to find whether they "equal" in your sense, whereas deep means that you compare contents of your objects recursively until all you need to compare is primitive fields. If you define equals method of your objects as sequence of calls to equals on instance fields of these objects, you use deep comparison. If you define equals using == operator to compare compound types, such as Strings, then you use shallow comparison -- and that's incorrect in Java.

Morale of all of this is that you must never use == to compare two compound objects, unless you consider them equal only if they are the same.

于 2011-04-18T13:43:28.143 回答
2

您所说的“浅相等”是身份:如果两个引用(即对象)是相同的实例,则它们是相同的。如果您知道其他语言中的指针是什么,则可以将标识与指针相等进行比较。

您所说的“深度相等”是相等:两个对象a并且b如果a.equals(b)返回则相等true(希望反之亦然)。相等的正确性很大程度上取决于equals方法的实现方式。有关更多详细信息,请参阅Object该类的 Javadoc。

于 2011-04-18T13:31:50.883 回答
2

首先:new Integer(0) == new Integer(0)永远不会评估为truenew 一如既往地创建一个新对象,回避任何可能存在的自动装箱缓存机制。

您可能听说过的是自动装箱(即在必要时将原始值自动转换为它们各自的包装类)。自动装箱使用的机制也可以使用包装类valueOf()方法访问。换句话说:将 an 自动装箱int到 an 的Integer工作原理与调用Integer.valueOf(int).

Integer.valueOf(0) == Integer.valueOf(0) 评估为true,因为公共值(即具有低绝对值的值)被缓存。当您连续调用两次时,您将获得相同的对象。 对于更高的值(例如您的示例中的 666),这不一定是正确的。IntegervalueOf(0)

于 2011-04-18T13:33:33.593 回答
1

equals() 测试两个对象是否本质上相同,但它可以为两个不同的对象返回 true;即,两个不同的回形针是“相等的”。引用类型的“==”测试两个引用是否引用同一个对象——即,一个回形针 == 只对它自己。== 测试identity,它equals测试equivalence

您可以有两个不同的 Integer 对象,其中包含 0(它们是equals());缓存意味着保存对象并在可能的情况下重用它们。

于 2011-04-18T13:31:10.737 回答