7

考虑两个调用静态工厂方法 valueOf 的 Integer 类型的引用,如下所示:-

    Integer a = Integer.valueOf("10"); 
    Integer b = Integer.valueOf("10"); 

考虑到 Integer 是不可变的,是否可以使用 == 而不是使用 equals 方法比较 a 和 b。我猜 valueOf 方法确保只创建一个值为 10 的 Integer 实例,并且为每个创建的值为 10 的 Integer 返回对该实例的引用。

一般来说,是否可以比较使用 == 而不是 equals 调用相同静态工厂方法创建的不可变类的两个引用?

编辑: Integer 类仅用作示例。我知道如果使用 == 进行比较,最多 127 的整数将返回 true。我需要知道的是,当我创建自己的不可变类时,例如使用方法 create() 的 MyImmutable,该方法将确保不会创建重复的 MyImmutable 对象,如果我比较使用 create 方法创建的 2 个 MyImmutable 引用是否可以使用 == 而不是等于。

4

5 回答 5

8

不,这通常不安全。==运算符比较引用,而不是值。

使用==恰好适用于 -128 到 127 之间的整数,但不适用于其他整数。以下代码演示了这==并不总是有效:

Integer a = Integer.valueOf(10); 
Integer b = Integer.valueOf(10); 
System.out.println(a == b);

true

Integer c = Integer.valueOf(1000); 
Integer d = Integer.valueOf(1000); 
System.out.println(c == d);

false

在线查看它:ideone

这种行为的解释在于实现Integer.valueOf

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);
 }

来源

也不是该标准要求小输入(-128 到 127)的装箱整数为对象提供相等的引用。

5.1.7 拳击转换

如果被装箱的值 p 是真、假、一个字节、一个在 \u0000 到 \u007f 范围内的字符,或者一个介于 -128 和 127 之间的 int 或短数字,则令 r1 和 r2 为任意两次装箱转换的结果p。r1 == r2 总是如此。

但是,该标准对超出此范围的整数没有做出此类保证。


一般来说,是否可以比较使用 == 而不是 equals 调用相同静态工厂方法创建的不可变类的两个引用?

如上所示,一般情况下它不会起作用。但是,如果您确保具有相同值的两个不可变对象始终具有相同的引用,那么是的,它可以工作。但是,您必须仔细遵守一些规则:

  • 构造函数不能是公共的。
  • 您通过静态方法创建的每个对象都必须被缓存。
  • 每次要求您创建对象时,您必须首先检查缓存以查看您是否已经创建了具有相同值的对象。
于 2012-06-10T17:41:55.340 回答
7

== 和 equals() 是根本不同的。

您应该阅读这篇文章以获取更多详细信息:

等于/等于和 == 运算符之间的区别?

它与不可变对象无关。

于 2012-06-10T17:42:07.753 回答
5

如果您的工厂方法为相同的输入返回相同的对象,那么将它们与 == 进行比较是安全的。例如 String.intern 就是这样工作的。枚举也可以与 == 进行比较。但是 Integer.valueOf 仅在 -128 ... 127 范围内返回相同的对象(在默认配置中)。

Integer.valueOf(127) == Integer.valueOf(127)

Integer.valueOf(128) != Integer.valueOf(128)

一般来说,您应该使用 equals 方法来比较任何对象。当对象有少量不同的值时,运算符 == 可用于提高性能。我不建议使用这种方法,除非你 100% 确定你在做什么。

于 2012-06-10T17:52:36.683 回答
2

不变性和平等并不一定相互关联。== 比较引用相等,这意味着,它比较两个变量是否指向对象的同一个实例。相等意味着两个对象共享相同的值。不变性现在意味着您不能在构造对象后对其进行更改。

因此,您可能有两个不可变对象,它们表示相同的值(意思是,它们相等,因此 a.equals(b) 返回 true)但它们不是同一个实例。

我在这里给你一个小例子:

公共类 MyPoint {
    私人int x;
    私人int y;

    公共MyPoint(int x,int y){
        这个.x = x;
        这个.y = y;
    }

    公共 int getX() {
        返回 x;
    }

    公共 int getY() {
        返回 y;
    }

    @覆盖
    公共布尔等于(对象 obj){
        if (!(obj instanceof MyPoint))
            返回假;
        我的点 p = (我的点) obj;
        返回 this.x == px && this.y == py;
    }

    /**
     * @param 参数
     */
    公共静态无效主要(字符串[]参数){
        我的点 p = 新的我的点 (2, 2);
        我的点 q = 新的我的点 (2, 2);
        我的点 r = q;

        System.out.println(p == q);
        System.out.println(p == r);
        System.out.println(q == r);
        System.out.println(p.equals(q));
        System.out.println(p.equals(r));
        System.out.println(q.equals(r));

    }

}

输出为: false false true true true true

MyPoint 是不可变的。初始化后,您无法更改其值/状态。但是,如您所见, myPoint 的两个对象可能是equal,但它们可能不是同一个实例。

我认为您想到的是某种享元模式,其中对于对象的每种可能状态仅存在一个对象。享元通常也意味着这些对象是不可变的。

于 2012-06-10T18:17:25.553 回答
1

它们不是同一个对象,所以==不会是真的。与对象,安全和使用equals()

于 2012-06-10T17:42:34.547 回答