2011-03-31 28 views
6

đây là mã của tôi:HashSet chứa phương pháp, kỳ lạ hành vi

public class testGui { 



    public static void main(String[] arg){ 
     class TESTS{ 
      String t; 

      public TESTS(String t){ 
       this.t = t; 
      } 

      @Override 
      public boolean equals(Object x){ 
       System.out.println("My method is called..."); 
       if(x instanceof TESTS){ 
        TESTS zzz = (TESTS) x; 
        return zzz.t.compareTo(t)==0; 
       } 
       else return false; 
      } 
     } 
     HashSet<TESTS> allItems = new HashSet<TESTS>(); 
     allItems.add(new TESTS("a")); 
     allItems.add(new TESTS("a")); 
     System.out.println(allItems.contains(new TESTS("a"))); 
    } 

} 

Tôi không hiểu tại sao HashSet chứa phương pháp không được gọi bằng phương pháp của tôi như mentionned trong thông số kỹ thuật của họ:

Nhiều chính thức , thêm phần tử được chỉ định, o, vào bộ này nếu tập hợp này không chứa phần tử e sao cho (o == null? e == null: o.equals (e))

Mã của tôi trả về false và không đi vào phương thức equals của tôi.

Cảm ơn bạn rất nhiều vì đã trả lời!

Trả lời

13

Khi ghi đè equals, bạn cũng phải ghi đè hashCode. Nếu không, các đối tượng bằng nhau sẽ có các mã băm khác nhau và được coi là không bằng nhau.

Bạn cũng không nên ghi đè chỉhashCode. Nhưng điều này là không cần thiết, vì các đối tượng không bằng nhau có thể có cùng mã băm.

+2

Chúng sẽ không được coi là không bằng nhau. Nó chỉ là HashSet thậm chí sẽ không gọi phương thức equals bởi vì nó chỉ làm cho hashCodes dẫn đến cùng một nhóm. Và chỉ ghi đè hashCode không có bất kỳ ý nghĩa nào, vì HashSet sẽ luôn gọi equals cho các đối tượng có cùng hashCodes. –

+0

@JB, vâng, thực tế là chúng dẫn đến các nhóm khác nhau có nghĩa là chúng được coi là 'không công bằng' (được coi là các đối tượng khác nhau). Tôi không đề cập đến phương thức 'equals' khi tôi sử dụng thuật ngữ đó. Tôi cũng đồng ý chỉ ghi đè 'hashCode' là vô lý, đó là lý do tại sao tôi khuyến khích mạnh mẽ chống lại nó. Tuy nhiên, nó không phá vỡ hợp đồng. –

+1

Nó sẽ là tốt đẹp nếu các tài liệu java đề cập rằng hashcode được gọi là đầu tiên. Tôi đã bị đốt cháy bởi vấn đề này trong java 5. – Aaron

3

Bạn cũng nên triển khai hashCode, sao cho phù hợp với equals. HashSet sử dụng phương pháp hashCode để quyết định nhóm nào sẽ đặt một mục vào và gọi equals chỉ khi mã băm của hai mục giống nhau.

Effective Java, 2nd Edition thảo luận quy tắc này (và những hậu quả của phá vỡ nó) trong Khoản 9: Luôn luôn ghi đè hashCode khi bạn ghi đè equals.

+0

Cảm ơn rất nhiều người, điều đó thực sự hữu ích, tôi đã tìm thấy câu trả lời trước khi bạn trả lời (không biết cách hủy câu hỏi), nhưng những gì bạn viết là những gì tôi đã làm và nó giải quyết vấn đề của tôi;). – Abbadon

7

HashSet phụ thuộc vào mã băm của từng đối tượng. Trước khi phương thức equals được gọi, phương thức hashCode sẽ được gọi. Nếu hashcodes bằng nhau, thì hashset coi nó xứng đáng với việc đánh giá phương thức equals.

Thực hiện một phương pháp hashcode ví dụ rằng nếu a.equals (b) == true, sau đó a.hashCode() == b.hashCode()

và nó sẽ bắt đầu làm việc như bạn mong đợi.

0

Vì hầu hết các nhận xét đã ... chỉ ghi đè phương thức hashcode (mẫu bên dưới) và bạn nên làm tốt.

@Override 
     public int hashCode() { 
      return t.hashCode()*31; 
     } 
+0

Bạn kiếm được gì bằng cách nhân với 31? –

+0

chuỗi này sẽ giúp http://stackoverflow.com/questions/299304/why-does-javas-hashcode-in-string-use-31-as-a-multiplier – Prasanna