2013-07-29 45 views
9

vì vậy tôi có một câu hỏi về phương pháp hashcode() và equals()hashcode() và equals() phương pháp

Hãy nói rằng tôi chỉ cần viết một chương trình rất cơ bản overridng cả methodes

import java.util.*; 

class Employee 
{ 
    private String name; 
    private int empid; 


    public Employee(String name,int empid) 
    { 
     this.name=name; 
     this.empid=empid; 
    } 


    public int getEmpid() 
    { 
     return empid; 
    } 


    public String getName() 
    { 
     return name; 
    } 


    public boolean equals(Object obj) 
    { 
     System.out.println("equals has just been called..."); 
     Employee e1=(Employee)obj; 
     return ((name.equals(e1.name)) && (empid==e1.empid)); 
    } 


    public int hashCode() 
    { 
     System.out.println("hashcode called..."); 
     return empid; 
    } 

} 

Sau đó, , giả sử tôi viết lớp khác để thêm và lặp các yếu tố trong HashSet

class Five 
{ 
    public static void main(String args[]) 
    { 
     HashSet hs1=new HashSet(); 
     hs1.add(new Employee("Alex",25)); 
     hs1.add(new Employee("Peter",25)); 
     hs1.add(new Employee("Martin",25)); 
     hs1.add(new Employee("Alex",25)); 


     Iterator itr=hs1.iterator(); 

     while(itr.hasNext()) 
     { 
      Employee e=(Employee)itr.next(); 
      System.out.println(e.getEmpid()+"\t"+e.getName()); 
     } 


    } 

} 

bây giờ câu hỏi là khi tôi cố gắng thêm Alex một lần nữa với cùng empID equals() luôn cal dẫn đến thời điểm

vì không có chỉ mục n hashmap vì vậy nếu lần đầu tiên được kiểm tra bằng Alex trước đó, nó sẽ trả về true và không được gọi cho hai phần tử khác (peter và martin) . 3 lần

lý do tại sao .. ??

là các đối tượng trong cùng một nhóm cũng có chỉ mục .. ??

+0

Tôi sẽ xem xét mã nguồn HashSet. Từ bộ nhớ nó thực sự thêm nó vào một bản đồ vì vậy tôi nghi ngờ indexOf và bằng được sử dụng nhiều lần trong đó – RNJ

+0

ankur Lathi- nopss que của tôi là khác nhau – sandiee

Trả lời

12

Equals luôn được gọi sau phương thức hashCode trong bộ sưu tập băm java trong khi thêm và xóa các phần tử. Lý do là, nếu có một phần tử đã có trong nhóm được chỉ định, thì JVM sẽ kiểm tra xem nó có phải là phần tử tương tự mà nó đang cố gắng đặt hay không. Trong trường hợp nếu giá trị bằng trả về false thì phần tử được thêm vào cùng một nhóm nhưng ở cuối danh sách tại nhóm. Vì vậy, bây giờ bạn chỉ cần không có một yếu tố duy nhất tại cùng một xô nhưng một danh sách các yếu tố.

Bây giờ khi truy xuất phần tử, hashCode đầu tiên sẽ được gọi để tiếp cận nhóm mong muốn và sau đó danh sách sẽ được quét bằng cách sử dụng dấu bằng để tìm nạp phần tử mong muốn.

Việc triển khai lý tưởng của hashCode sẽ đảm bảo kích thước danh sách tại mỗi nhóm là 1. Và do đó việc truy xuất các phần tử được thực hiện bằng cách sử dụng độ phức tạp O (1). Nhưng nếu có các phần tử mulitple được lưu trữ trong danh sách tại một xô, thì sự tái chiếm của phần tử sẽ được thực hiện bởi O (n) complexiy, trong đó n là kích thước của danh sách.

Btw trong trường hợp HashSet không có danh sách nào được tạo tại thùng, thay vào đó đối tượng được thay thế đơn giản nếu hashcode và bằng nhau giống nhau. Hành vi tạo ist là trong hashmap.

+2

Tôi nghĩ rằng cuộc gọi phương thức hashCode được theo sau bởi cuộc gọi bằng phương thức ... – Puce

+1

@Puce Không, hashCode luôn được gọi là đầu tiên để nhận được nhóm, và sau đó bằng được gọi để kiểm tra mọi thứ tại nhóm đó. –

+0

juned ahsan- thnx sir .. phải mất một thời gian nhưng bây giờ đã nhận nó và giải thích về sự phức tạp là điểm tôi muốn – sandiee

0

Nhiều đối tượng có cùng một băm được lưu trữ dưới dạng LinkedList và các thành phần mới được thêm tại HEAD. Vì vậy, trong trường hợp của bạn vì tất cả đều có cùng một mã băm, LinkedList theo thứ tự sau:

Martin-> Peter-> Alex.

Khi bạn thêm một "Alex" khác, danh sách này được chuyển từ HEAD.

Để kiểm tra:

public boolean equals(Object obj) 
    { 
     Employee e1=(Employee)obj; 
     System.out.println(this.name + "'s equals has just been called against " + e1.name); 
     return ((name.equals(e1.name)) && (empid==e1.empid)); 
    } 
3

Trong chèn các HashSet cuộc gọi đầu tiên hashCode và trông trong đó bộ chứa giá trị mới thuộc về. Nó thấy rằng đã có ba mục (tất cả đều có hashCode()25).

Vì vậy, sau đó so sánh bằng cách sử dụng equals().Và bởi vì có 3 mục, nó phải kiểm tra tất cả các mục gây ra để gọi equals() 3 lần.

+1

Tôi ban đầu nghĩ rằng anh ta đã vi phạm hợp đồng 'equals()' và 'hashCode()', nhưng làm sao nó có thể ảnh hưởng đến bất cứ thứ gì? Nếu chúng có cùng 'empid', chúng ánh xạ tới cùng một khe mảng, và sau đó' equals' được sử dụng để xem nếu 'tên' khớp với nhau. Tôi không thể thấy vấn đề ... –

+3

Phương thức 'equals' và' hashCode' trông ổn với tôi - 'equals' sử dụng cả hai trường' name' và 'empid' trong khi' hashCode' chỉ sử dụng 'empid'. Điều này không xác nhận hợp đồng cho biết 'các đối tượng bằng nhau nên có cùng mã băm, nhưng cùng một mã băm không có nghĩa là các đối tượng bằng nhau'. –

+0

Trên thực tế, tôi nghĩ rằng nó chỉ có để so sánh các mục miễn là bằng trả về false, nhưng có thể dừng lại một lần bằng trả về đúng sự thật. Vì vậy, điều này có thể có nghĩa là mục nhập đầu tiên ("Alex", 25) nằm ở cuối danh sách vì một số lý do? – Puce

3

A java.util.HashSet sử dụng bộ nhớ java.util.HashMap làm bộ nhớ. A java.util.HashMap sử dụng đối tượng Entry được liên kết để thể hiện các nhóm trong bản đồ. Nếu bạn làm theo thông qua các mã nguồn mà bạn sẽ đến được với các contructor của java.util.HashMap.Entry:

Entry(int h, K k, V v, Entry<K,V> n) 
{ 
    value = v; 
    next = n; 
    key = k; 
    hash = h; 
} 

Từ đây bạn có thể thấy rằng các mặt hàng mới được thêm vào khi bắt đầu xô (các Entry n đại diện cho Entry đầu tiên của xô) , vì vậy trong trường hợp của bạn các mục trong xô (chỉ có một xô đơn vì mã băm cho mỗi Employee là như nhau) sẽ được theo thứ tự:

Martin -> Peter -> Alex 

do đó khi thêm Alex một lần thứ hai, mỗi giá trị được kiểm tra bình đẳng trước khi đến Alex.