2012-02-03 35 views
5

Tôi có một lớp Point tùy chỉnh đơn giản như sau và tôi muốn biết nếu implemention hashCode của tôi có thể được cải thiện hoặc nếu điều này là tốt nhất nó sẽ nhận được.Java hashCode cho một lớp Point

public class Point 
{ 
    private final int x, y; 

    public Point(int x, int y) 
    { 
     this.x = x; 
     this.y = y; 
    } 

    public int getX() 
    { 
     return x; 
    } 

    public int getY() 
    { 
     return y; 
    } 

    @Override 
    public boolean equals(Object other) 
    { 
     if (this == other) 
      return true; 

     if (!(other instanceof Point)) 
      return false; 

     Point otherPoint = (Point) other; 
     return otherPoint.x == x && otherPoint.y == y; 
    } 


    @Override 
    public int hashCode() 
    { 
     return (Integer.toString(x) + "," + Integer.toString(y)).hashCode(); 
    } 

} 
+1

Bạn đang cố gắng để cải thiện nó? Bạn có muốn thử nhanh hơn không? – David

+0

bạn muốn đảm bảo tính duy nhất? tốc độ? – Adrian

+0

Tôi muốn đảm bảo cả hai :) –

Trả lời

8

Xin đừng dùng Strings. Có rất nhiều lý thuyết đằng sau điều này và một số triển khai (phương pháp phân chia, nhân một, v.v ...). Nếu bạn có khoảng một tiếng đồng hồ bạn có thể xem này MIT-Class

này đang được nói, đây là những gì Netbeans 7.1 cho thấy:

@Override 
public int hashCode() { 
    int hash = 7; 
    hash = 71 * hash + this.x; 
    hash = 71 * hash + this.y; 
    return hash; 
} 

tháng 10 năm 2015 Sửa

tôi bắt đầu sử dụng IntelliJ một thời gian trở lại, Tôi sống hạnh phúc hơn bây giờ. Đây là những gì tạo ra hashCode tự động của nó. Đó là một chút ít tiết. Lưu ý việc sử dụng các số nguyên tố là tốt.

@Override 
public int hashCode() { 
    int result = x; 
    result = 31 * result + y; 
    return result; 
} 
+0

+1 Thú vị là Netbeans gợi ý điều gì đó khác với nhật thực, nhưng cơ sở cho việc thực hiện là tương tự và vững chắc. – nybbler

+0

Tôi đang bối rối, cách triển khai thứ hai thực hiện tốt như thế nào? Bạn nhận được va chạm ngay cả với số lượng rất nhỏ, như (0,31), (1,0). Điều đó có vẻ rất bất lợi, phải không? –

+0

@ChristopherShroba của bạn là một nhận xét rất thú vị và tôi sẽ xem xét điều đó khi tôi trở về sau kỳ nghỉ! Vấn đề chính là 'kết quả' được khởi tạo với' 0' cho đầu vào mẫu của bạn. Tuy nhiên, đó là những gì IntelliJ 2016 làm ... – Gevorg

0

tôi sử dụng để viết băm của riêng tôi và bằng chức năng sau đó tôi thấy điều này:)

import org.apache.commons.lang.builder.HashCodeBuilder; 
import org.apache.commons.lang.builder.EqualsBuilder; 

@Override 
public boolean equals(Object obj) { 
    return EqualsBuilder.reflectionEquals(this, obj); 
} 
@Override 
public int hashCode() { 
    return HashCodeBuilder.reflectionHashCode(this); 
} 

tất nhiên cần lưu ý những điều sau:

Bởi vì phản ánh liên quan đến loại đó là tự động giải quyết, một số tối ưu hóa máy ảo Java không thể thực hiện được. Do đó, hoạt động phản xạ có hiệu suất chậm hơn so với các đối tác không phản chiếu của họ, và nên tránh trong các phần của mã được gọi là thường xuyên trong các ứng dụng hiệu suất nhạy cảm. SRC

+0

Vì chỉ có hai trường, bạn cũng có thể sử dụng thư viện này, nhưng rõ ràng liệt kê các trường. –

+0

Nếu lớp này được sử dụng đáng kể trong Bộ sưu tập, một hashCode phản chiếu sẽ là một hit hiệu suất lớn. – user949300

+1

Tôi khuyên bạn nên sử dụng ['HashCodeBuilder.append'] (http://commons.apache.org/lang/api-2.5/org/apache/commons/lang/builder/HashCodeBuilder.html#append%28int%29) thay vào đó. –

2

tôi sẽ khuyên bạn sử dụng một phương pháp đơn giản và performant hơn mà không dây, có lẽ phương pháp Josh Bloch từ this answer, trong trường hợp của bạn chỉ cần:

return 37 * x + y; 

EDIT: nybbler là đúng. Điều gì đang thực sự đề nghị là:

int result = 373; // Constant can vary, but should be prime 
result = 37 * result + x; 
result = 37 * result + y; 
+1

Đó không phải là những gì được đề xuất trong câu trả lời được liên kết của bạn. Bạn đã bỏ lỡ điều này nên được thực hiện cho mọi trường ** riêng **, không phải cùng một lúc. Thuật toán này tạo ra kết quả tương tự cho [0,37] và [1,0] – nybbler

+0

Lưu ý rằng triển khai mới sẽ vẫn tạo ra xung đột cho bất kỳ cặp Điểm nào trong biểu mẫu (x, 37y), (y, 37x) .. – Gevorg

0

Từ lớp Point của JDK (thừa hưởng từ Point2d):

public int hashCode() { 
    long bits = java.lang.Double.doubleToLongBits(getX()); 
    bits ^= java.lang.Double.doubleToLongBits(getY()) * 31; 
    return (((int) bits)^((int) (bits >> 32))); 
} 

Điều đó có vẻ tốt hơn một chút so với thực hiện của bạn.

0

Bạn có thể có một cái nhìn vào kiểu Point lớp hiện thực hiện:

/** 
343  * Returns the hashcode for this <code>Point2D</code>. 
344  * @return a hash code for this <code>Point2D</code>. 
345  */ 
346  public int hashCode() { 
347  long bits = java.lang.Double.doubleToLongBits(getX()); 
348  bits ^= java.lang.Double.doubleToLongBits(getY()) * 31; 
349  return (((int) bits)^((int) (bits >> 32))); 
350  } 

từ: http://kickjava.com/src/java/awt/geom/Point2D.java.htm#ixzz1lMCZCCZw

hướng dẫn đơn giản để thực hiện hashCode thể được tìm thấy here

+0

Lời cảnh báo cho tất cả những người sử dụng thông tin này để nhận dạng. Hash va chạm là một thực tế ... Ví dụ pastebin.com/6wM3W3Wv – vincent

0

Theo mặc định, Eclipse sẽ sử dụng một hashCode() chức năng cho lớp Point của bạn tương tự như:

@Override 
public int hashCode() { 
    final int prime = 31; 
    int result = 1; 
    result = prime * result + getOuterType().hashCode(); 
    result = prime * result + x; 
    result = prime * result + y; 
    return result; 
} 

Ít nhất, việc kết hợp một số nguyên tố vào thuật toán hashCode của bạn sẽ giúp với "tính duy nhất".

+0

Có lẽ bạn đã viết sai "Java" thay vì "Eclipse". Theo mặc định, 'hashCode'" thường được thực hiện bằng cách chuyển đổi địa chỉ nội bộ của đối tượng thành một số nguyên. " –

+0

@MatthewFlaschen Thật vậy, tôi đã làm. Đã cập nhật ngay bây giờ; cảm ơn vì đã bắt được điều đó. – nybbler

5

Việc nhân các giá trị của tất cả các trường thành viên quan trọng như Gevorg đề xuất có lẽ hiệu quả nhất và có phân phối giá trị tốt. Tuy nhiên, nếu bạn thích có thể đọc, có những lựa chọn thay thế tốt đẹp sẵn có hoặc trong Java 7 ...

import java.util.Objects; 

... 

@Override 
public int hashCode() { 
    return Objects.hash(x, y); 
} 

... hoặc trong Guava thư viện:

import com.google.common.base.Objects; 

.... 

@Override 
public int hashCode() { 
    return Objects.hashCode(x, y); 
} 

Cả hai phương pháp đơn giản varags uỷ thác cho Arrays.hashCode(Object[] a), do đó, có một tác động nhỏ đến hiệu suất do hộp số tự động của int và tạo một mảng tham chiếu đối tượng, nhưng nó sẽ ít quan trọng hơn nhiều so với việc sử dụng sự phản chiếu.

Và khả năng đọc chỉ là tuyệt vời, vì bạn chỉ đơn giản là nhìn thấy, mà các lĩnh vực được sử dụng cho việc tính toán hashcode và tất cả các nhân và thêm cú pháp chỉ là ẩn dưới mui xe của Arrays.hashCode(Object[] a):

public static int hashCode(Object a[]) { 
    if (a == null) 
     return 0; 

    int result = 1; 

    for (Object element : a) 
     result = 31 * result + (element == null ? 0 : element.hashCode()); 

    return result; 
} 
+0

Vẫn còn dễ bị tổn thương đối với bất kỳ cặp nào trong biểu mẫu '(x, 31y), (y, 31x)' ví dụ (0, 31), (1, 0) hoặc (3, 217), (7, 93). Tôi đang cố gắng châm ngòi cho một cuộc thảo luận rộng rãi ở đây. Có cách nào để có một thực hiện mạnh mẽ hơn hoặc chỉ với 2 số nguyên phải đối phó với loại vấn đề này (phụ thuộc vào số nguyên tố được sử dụng trong việc tạo mã băm)? – Gevorg

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