【问题标题】:How to ensure the hashcode does not equal another object of same type by chance如何确保哈希码不等于另一个相同类型的对象
【发布时间】:2014-01-13 16:57:49
【问题描述】:

我正在尝试使用复制构造函数来克隆车辆对象。为了演示,我重写了一个名为 Vehicle 的类的toString() 方法。但克隆必须是唯一且完全独立的。

如果我创建了数千个 Vehicle 对象的克隆,是否可以保证在使用 equals() 方法相互检查时它们都是唯一的?我的印象是,当我使用equals() 方法进行比较时,可以保证创建的每个对象始终具有一个新的唯一哈希码,该哈希码永远不会相等。

已编辑: 我的问题真的是,使用默认的 equals() 方法来比较我的 100000 个克隆是否会确保每个克隆实际上都是唯一的,而 equals() 将始终返回 false ???

public class App {

    public List<Vehicle> buildCar(String type, int hp)
    {
        List<Vehicle> vs = new ArrayList<Vehicle>();
        Vehicle vObject = new Vehicle();
        vObject.setHorsePower(hp);
        vObject.setType(type);

        Vehicle newV = new Vehicle(vObject);
        vs.add(newV);
        vs.add(vObject);
        return vs;
    }   

    public static void main(String args[]){
        App ap = new App();
        List<Vehicle> vehicles = new ArrayList<Vehicle>();

        vehicles.addAll(ap.buildCar("car",100));

        Vehicle v1 = vehicles.get(0);
        Vehicle v2 = vehicles.get(1);

        System.out.println(v1.equals(v2)); // prints false.
                //System.out.println(v2.hashCode());

    }
}

【问题讨论】:

  • 哈希码并不意味着唯一,只有As much as is reasonably practical
  • 那么 equals() 方法是否默认使用 hashcode 来检查相等性?如何使用 equals() 等方法确保克隆在我的 java 代码检查中是单独的?
  • 阅读每个方法的javadoc。您的 equals() (Indicates whether some other object is "equal to" this one.) 不应在内部使用 hashcode() (Returns a hash code value for the object.)。
  • 是的,但是看看文档对 equals() 方法的说法:Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes. 基本上我的问题是这样的:在使用它进行比较时,我可以依赖默认的 equals() 方法是正确的吗100000 个相互克隆?
  • 不,你不能依赖默认的 equals。阅读完整的 javadoc 条目。默认的equals 只检查与== 的引用相等性。

标签: java hashcode


【解决方案1】:

这是错误的。 hashCode() 函数返回 int。所以在创建2^32 + 1对象时,至少有一个哈希码会出现两次。

默认情况下(如果您不覆盖hashCode() 函数),对象将在内存中的地址作为哈希码。这就是为什么你会觉得它是独一无二的。您创建的对象不足以分配足够的内存来获得两个相等的哈希码。


如何确保通过克隆生成的对象实际上是完全独立且唯一的?

独立性和独特性是不同的标准。

独立意味着一个对象和它的克隆不共享状态。因此,如果(例如)您的 Vehicle 对象具有可变组件,您需要确保您的 clone 方法也克隆组件。

唯一性需要更多信息。具体来说,这取决于您使用什么作为唯一性“测试”。

  • 如果您使用== 作为唯一性测试,那么任何创建新对象的clone 实现都将满足要求。 (clone 的正常期望是它创建一个新对象...)

  • 如果您使用equals 作为唯一性测试,那么这取决于您如何定义equals 方法。 equals 的默认实现使用 ==。如果您覆盖equals 以基于对象字段进行测试,那么如果您希望克隆是唯一的(根据equals),您需要某种标识符字段用作对象身份。 .. 并安排您的 clone 方法为每个克隆提供一个新的标识符值。 (这意味着仅仅委托给Object.clone() 是不够的。)


我的问题是,使用默认的 equals() 方法来比较我的 100000 个克隆是否会确保每个克隆实际上都是唯一的,并且 equals() 将始终返回 false?

是的......对于clone()的任何合理实现。

Java equals(Object) 的默认实现与 Java == 执行相同的测试,并且仅当两个操作数是相同的对象引用时才会为您提供 true

【讨论】:

  • 好的,所以我不想在这个可怕的假设上构建软件。如何确保通过克隆生成的对象实际上是完全独立且唯一的?我希望能够在我的 java 代码中检查它。
  • 好吧,如果你想这样做,你可以查看参考。只需使用== 而不是equals(Object)。每个对象都有一个唯一的引用。
【解决方案2】:

如果您使用任何正确的clone 实现,则结果是与原始对象不同的对象(即original.clone() != original)。

Object 的 equals 实现检查对象是否相同(返回值与 == 相同),即只要正确实现了 clone(),它就不会为克隆返回 true。 基本上您可以将 o.equals(o2) 视为检查,如果 2 个对象,变量 o 和 o2 引用占用相同的内存。 (仍在谈论非覆盖的 equals 实现)

因此,如果您使用等号检查,克隆和原始将成对不同。

【讨论】:

    【解决方案3】:

    equals 方法将始终以 100% 的准确率区分相等(无论是什么意思)和不相等。仅当哈希码不匹配时,才保证比较哈希码意味着“不相等”——相等的哈希码并不意味着“相等”将为真。

    哈希码的一条牢不可破的规则是,如果两个对象“相等”返回 true,那么它们的哈希码必须匹配。

    【讨论】:

      猜你喜欢
      • 2013-04-30
      • 2011-07-23
      • 2017-12-16
      • 1970-01-01
      • 1970-01-01
      • 2020-06-22
      • 1970-01-01
      • 1970-01-01
      • 2011-10-21
      相关资源
      最近更新 更多