2009-06-30 40 views
10

Hành vi mặc định của Object.hashCode() là trả về cơ bản "địa chỉ" của đối tượng sao cho a.hashCode() == b.hashCode() nếu và chỉ khi a == b . Làm thế nào tôi có thể nhận được hành vi này trong một lớp người dùng định nghĩa nếu một superclass đã định nghĩa hashCode()? Ví dụ:Mã băm Java dựa trên danh tính

class A { 
    public int hashCode() { 
    return 0; 
    } 
} 

class B extends A { 
    public int hashCode() { 
    // Now I want to return a unique hashcode for each object. 
    // In pythonic terms, it'd look something like: 
    return Object.hashCode(this); 
    } 
} 

Ý tưởng?

+1

Không. Đó là lấy mã để a.hashCode()! = B.hashCode() ngụ ý nhất thiết là a! = B. –

+3

... nhưng a.hashCode() == b.hashCode() không ngụ ý một == b tôi nên có thêm. –

+1

nếu "a.equals (b)", không nhất thiết phải "a == b", thì mã băm phải bằng nhau: "a.hashCode() == b.hashCode()" –

Trả lời

25

System.identityHashCode(Object) cung cấp hành vi này.

Bạn sẽ viết này:

class B extends A { 
    public int hashCode() { 
    return System.identityHashCode(this); 
    } 
} 

Vui lòng kiểm tra các bằng-phương pháp, mà nó chỉ trả về true, nếu hai đối tượng đều giống nhau. Nếu không, nó sẽ vi phạm hành vi được mô tả cho equalshashCode. (Để chính xác, phương thức equals phải trả về false, nếu bạn nhận được hashcodes khác nhau cho hai đối tượng.) Để cung cấp việc thực thi bằng() tuân thủ phương thức hashCode() đã cho:

public boolean equals(Object other){ 
    return this == other; 
} 
9

Sử dụng System.identityHashCode(). Đây là những gì sử dụng IdentityHashMap.

Bạn nên cực kỳ cảnh giác với trọng một hiện hashCode() với điều này bởi vì mặc dù bạn có thể phá vỡ hợp đồng hashCode, là hai đối tượng:

nếu a.equals (b) sau đó a.hashCode() phải bằng b.hashCode()

Bạn có thể phá vỡ điều này bằng cách ghi đè hành vi hiện tại hoặc bạn cũng có thể cần ghi đè bằng().

1

Như Mnementh đã nói tất cả, tôi chỉ muốn chỉ ra rằng hashCode() trả về 0 (hoặc bất kỳ giá trị không đổi) nào là hợp lệ (trong khi lame). Hàm hashCode() có thể (và nên) trả về các giá trị khác nhau cho a và b chỉ khi! a.equals (b).
Vì vậy, ví dụ bạn có

class A { 
    public int hashCode() { 
    return 0; 
    } 
    public boolean equals(Object o) { 
    return o instanceof A; // all objects are equal 
    } 
} 

class B extends A { 
    public int hashCode() { 
    return System.identityHashCode(this); 
    } 
    public boolean equals(Object o) { 
    return this.hashCode().equals(o.hashCode()); 
    } 
} 

Bây giờ bạn tạo ra hai đối tượng:

A a = new A(); 
A b = new B(); 

Và đột nhiên a.equals (b), nhưng b.equals (a)!. Tất nhiên trong cuộc sống thực hơn bằng() trong A sẽ phức tạp hơn, nhưng vấn đề vẫn còn tồn tại. Để loại bỏ vấn đề này, bạn muốn luôn gọi

if (super.equals(o)) return true; 

vào đầu mới bằng().

Và kể từ khi hashCode() được gắn chặt với giá trị bằng(), bạn muốn đảm bảo rằng mọi nơi super.equals() trả về true cho hai đối tượng nhất định, hashCode mới() sẽ trả về super.hashCode() .

Các vấn đề liên quan