简体   繁体   English

为什么这个HashMap.get返回null?

[英]Why does this HashMap.get return a null?

I'm trying to create a Hashmap to perform a lookup for me. 我正在尝试创建一个Hashmap来为我执行查找。 However when I run this test code, the output is null. 但是,当我运行此测试代码时,输​​出为空。 I think it has to due with the nature of how the keys are being stored, but Im not positive. 我认为它必须与密钥的存储方式有关,但我并不积极。 Maybe it's a similar quirk like how the var1 == var2 are not equals unless they point to the same Object in memory, instead you have to use the var1.equals(var2) ? 也许这是一个类似的怪癖,就像var1 == var2不等于它们,除非它们指向内存中的同一个对象,而你必须使用var1.equals(var2)

There are two classes to test this. 有两个类可以测试它。

TestCard.java TestCard.java

import java.util.HashMap;

public class TestCard {

     // HashMap for SpecialK Lookup
    private static HashMap<Card, Integer> specialKLookup = new HashMap<Card, Integer>();

    // Constructor
    public TestCard(){
    }

    public static void main(String[] args) {
        Card[] cards = new Card[3];
        cards[0] = new Card((short)12, (short)0);
        cards[1] = new Card((short)0, (short)1);
        cards[2] = new Card((short)5, (short)2);

        /* Build SpecialK Lookup HashMap.
         * Ace of Spades = 0
         * Ace of Hearts = 1
         * Ace of Diamonds = 2
         * Ace of Clubs = 3
         * ...
         * Two of Clubs = 51
         */
        Integer specialKCounter = 0;
        for(int i=12;i>=0;i--){
                for (int j=0;j<4;j++){
                        specialKLookup.put(new Card((short)i, (short)j), specialKCounter++);
                }
        }

        System.out.println(specialKLookup.get(cards[0]));
    }
}

Card.java Card.java

public class Card{
    private short rank, suit;

    private static String[] ranks = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace"};
    private static String[] suits = {"Spades", "Hearts", "Diamonds", "Clubs"};

    //Constructor
    public Card(short rank, short suit){
        this.rank = rank;
        this.suit = suit;
    }

    // Getter and Setters
    public short getSuit(){
        return suit;
    }

    public short getRank(){
        return rank;
    }

    protected void setSuit(short suit){
        this.suit = suit;
    }

    protected void setRank(short rank){
        this.rank = rank;
    }   
}

The class ( Card ) is missing a proper implementation of equals(Object) and hashCode() 类( Card )缺少equals(Object)hashCode()的正确实现

Without both of these defined it will just not work . 如果没有这两个定义, 它将无法正常工作 (It compiles fine because these methods are both virtual and inherited in all objects as they are part of Object: HashMap can't enforce this at compile-time.) See the links above for the contract that is required. (它编译得很好,因为这些方法都是虚拟的,并且在所有对象中都是继承的,因为它们是Object的一部分:HashMap在编译时不能强制执行此操作。)请参阅上面的链接以获取所需的合同。

Both of these methods are required to be implemented because hashCode determines the hash-bucket used in the HashMap implementation and equals is to ensure that an object is value-equals (multiple objects can have the same hashCode , which is why equals is also required). 这两个方法都需要实现,因为hashCode确定HashMap实现中使用的hash-bucket, equals是确保对象是value-equals(多个对象可以具有相同的hashCode ,这也是为什么还需要equals ) 。 See Hash table for more general hash details. 有关更多常规哈希详细信息,请参阅哈希表

If these methods are not overloaded then the implementations defined in Object are used. 如果这些方法没有重载,则使用Object中定义的实现。 That is, x.equals(y) has near- x == y semantics and hashCode returns a stable number per contract. 也就是说, x.equals(y)具有near- x == y语义, hashCode每个合约返回一个稳定的数字。 This effectively makes the map work like an identity map (when Card objects are keys): only the exact same object can retrieve a previously stored value -- every other get will return null, as observed. 这有效地使地图像身份地图一样工作(当Card对象是键时):只有完全相同的对象才能检索先前存储的值 - 每个其他get将返回null,如所观察到的那样。

Happy coding. 快乐的编码。

It is indeed exactly because of this issue. 确实正是因为这个问题。

You need to define what equality means on cards, so you need to override the equals and hashCode methods. 您需要定义卡上的相等性,因此您需要覆盖equalshashCode方法。

If you do not, it assumes that two cards are only equal if they're the same instance. 如果不这样做,则假定两张牌只是相同的,如果他们是同一个实例。 (As in the default behavior of equals .) (与equals的默认行为一样。)

Note that, it is very important you override both equals and hashCode , as two objects that're equal must hash to the same value for a HashMap to work correctly. 请注意,覆盖equalshashCode非常重要,因为两个相等的对象必须散列到相同的值才能使HashMap正常工作。

For more information, see Overriding equals and hashCode in Java . 有关更多信息,请参阅在Java中覆盖equals和hashCode

Maybe it's a similar quick like how the var1 == var2 are not equals unless they point to the > same Object in memory, instead you have to use the var1.equals(var2) 也许它类似于var1 == var2不等于的速度,除非它们指向内存中的>相同的Object,而是必须使用var1.equals(var2)

Almost. 几乎。 As you would expect, a hash map needs a way of getting hash codes for your objects. 正如您所料,哈希映射需要一种获取对象哈希码的方法。 In Java, this is provided by the hashCode method which is implemented by Object, but needs to be overridden by your Card class. 在Java中,这是由Object实现的hashCode方法提供的,但需要由Card类覆盖。

*update: as pst points out, it must also reimplement equals. *更新:正如pst指出的那样,它也必须重新实现等于。

You need to implement the hashCode and equals methods, since this allows equality testing on two different objects, and also helps with hash map storage. 您需要实现hashCode和equals方法,因为这允许在两个不同的对象上进行相等性测试,并且还有助于哈希映射存储。 Without implementing these, two objects will be seen as distinct even if their properties are the same. 如果不实现这些,即使它们的属性相同,也会看到两个对象是不同的。 See http://www.jchq.net/certkey/0902certkey.htm for more details. 有关详细信息,请参见http://www.jchq.net/certkey/0902certkey.htm

Card should override equals and hashCode . 卡应该覆盖equalshashCode Take a look here: http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html 看看这里: http//www.ibm.com/developerworks/java/library/j-jtp05273/index.html

You'll have to override the hashCode() method for Card and make it return the same value if and only if the cards are equal - you should override equals() too. 你必须覆盖CardhashCode()方法并使其返回相同的值,当且仅当卡片相等时 - 你也应该重写equals() Because that's what the HashMap relies on in order to find the objects referenced by the keys; 因为这是HashMap依赖的,以便找到键引用的对象; as it stands now, it's the versions of those methods inherited from Object that are being used, which will only match if you use the same objects as keys, whereas you're creating new, albeit 'equal', ones. 就像现在一样,它是继承自Object的那些方法的版本,只有当你使用相同的对象作为键时,才会匹配,而你创建新的,虽然是“相等”的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM