簡體   English   中英

Java HashMap包含奇怪的行為

[英]Java HashMap containsKey strange behavior

試圖實現簡單的任務陷入奇怪的問題:

class User{
    String login;
    String pwrd;
    User(String lg,String pw){
        this.login=lg;
        this.pwrd=pw;
    }
    public String toString(){
        return this.login;
    }
    public boolean equals(String a){
        return this.login.equals(a);
    }
    public boolean equals(User t){
        return this.login.equals(t.toString());
    }
}

public class Foo{
    public static void main (String[] args)
    {
        HashMap<User,Boolean> a=new HashMap<>();
        User a1=new User("asd","123"),a2=new User("asd","134");
        a.put(a1,false);
        a.put(a2,false);
        System.out.println(a.containsKey(a2));
        System.out.println(a.containsKey("asd"));
    }
}

結果我期望containsKey檢查都是真的。 進一步在代碼中它將被越來越多地使用。 所以首先要理解為什么它表現如此,如果可能的話修復它。 任何幫助贊賞。

Map的鍵是User實例,因此a.containsKey("asd")永遠不會返回true ,因為“asd”是一個String。

順便說一下,你沒有覆蓋Objectequals ,它需要一個Object參數。 這意味着a.containsKey(a2)也返回false ,因為a1==a2為false。

正確實現equals將是:

@Override
public boolean equals(Object other){
    if (!(other instanceof User))
        return false;
    User u = (User) other;
    return this.login.equals(u.login);
}

正如Andy所提到的,你還必須覆蓋hashCode ,這樣如果a.equals(b)為true,那么a.hashCode()==b.hashCode()

編輯:

我認為你可以使a.containsKey("asd")返回true,如果你以一種將String實例視為等於你的User實例的方式覆蓋equals ,如果它們與login屬性匹配:

@Override
public boolean equals(Object other){
    if (other instanceof User) {
        User u = (User) other;
        return this.login.equals(u.login);
    } else if (other instanceof String) {
        String u = (String) other;
        return this.login.equals(u);
    }
    return false;
}

@Override
public int hashCode()
{
    return login.hashCode();
}

我從未嘗試過這樣的equals實現,但根據我對HashMap理解,它可能會起作用。

但是,這樣的equals實現會違反Javadoc of Object定義的equals的合同,因為即使a1.equals("asd")為真, "asd".equals(a1)也會返回false。

編輯:

在檢查HashMap的實現之后,我發現equals這個實現將不起作用,因為containsKey(key)的代碼將鍵與現有條目的鍵進行比較而不是相反的方式,並且String.equals(obj)如果obj不是String它將始終返回false。 我想有一個很好的理由不打破equals合同。

您需要覆蓋public boolean equals(Object other)並在該方法內部檢查傳遞的其他對象的正確類型。 請注意,傳遞的對象也可能為null

public class User {
  public boolean equals(Object other) {
    //Is the same
    if(other == this) {
      return true;
    }
    //Other is a user as well - Includes null-check (thanks, Kevin!)
    if(other instanceof User) {
      //equal if usernames are equal
      return login.equals(other.login);
    }
    //anything else - not equal / null, whatever
    return false;
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM