java 为什么这个 HashMap.get 返回空值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6078207/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does this HashMap.get return a null?
提问by ProfessionalAmateur
I'm trying to create a Hashmap
to perform a lookup for me. 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)
?
我正在尝试创建一个Hashmap
来为我执行查找。但是,当我运行此测试代码时,输出为空。我认为这与密钥存储方式的性质有关,但我并不乐观。也许这是一个类似的怪癖,就像var1 == var2
除非它们指向内存中的同一个对象,否则不相等,而您必须使用var1.equals(var2)
?
There are two classes to test this.
有两个类来测试这个。
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
卡.java
public class Card{
private short rank, suit;
private static String[] ranks = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "Hyman", "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;
}
}
回答by
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). See Hash tablefor more general hash details.
这两个方法都需要实现,因为hashCode
决定了 HashMap 实现中使用的 hash-bucket 并且equals
是为了确保一个对象是 value-equals(多个对象可以具有相同的hashCode
,这就是为什么equals
也需要)。有关更一般的哈希详细信息,请参阅哈希表。
If these methods are not overloaded then the implementations defined in Object are used. That is, x.equals(y)
has near-x == y
semantics and hashCode
returns a stable number per contract. This effectively makes the map work like an identity map(when Card objects are keys): only the exact same objectcan retrieve a previously stored value -- every other get will return null, as observed.
如果这些方法没有重载,则使用 Object 中定义的实现。也就是说,x.equals(y)
具有接近x == y
语义并hashCode
为每个合约返回一个稳定的数字。这有效地使映射像身份映射一样工作(当 Card 对象是键时):只有完全相同的对象才能检索以前存储的值——正如观察到的那样,每个其他获取都将返回 null。
Happy coding.
快乐编码。
回答by Sebastian Paaske T?rholm
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.
您需要定义卡片上的相等性意味着什么,因此您需要覆盖equals
和hashCode
方法。
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 musthash to the same value for a HashMap
to work correctly.
请注意,覆盖equals
and非常重要hashCode
,因为两个相等的对象必须散列到相同的值才能使 aHashMap
正常工作。
For more information, see Overriding equals and hashCode in Java.
有关更多信息,请参阅在 Java 中覆盖 equals 和 hashCode。
回答by Jacob
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 不等于,除非它们指向内存中的 > 相同对象,而您必须使用 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 methodwhich 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指出的那样,它还必须重新实现equals。
回答by Anthony Accioly
Card should override equals
and hashCode
.
Take a look here: http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html
卡应该覆盖equals
和hashCode
。看看这里:http: //www.ibm.com/developerworks/java/library/j-jtp05273/index.html
回答by Chris Dennett
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. Without implementing these, two objects will be seen as distinct even if their properties are the same. See http://www.jchq.net/certkey/0902certkey.htmfor more details.
您需要实现 hashCode 和 equals 方法,因为这允许对两个不同对象进行相等性测试,并且还有助于哈希映射存储。如果不实现这些,即使它们的属性相同,两个对象也会被视为不同的。有关更多详细信息,请参阅http://www.jchq.net/certkey/0902certkey.htm。
回答by entonio
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. Because that's what the HashMap
relies on in order to find the objects referenced by the keys; 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.
当且仅当卡片相等时,您必须覆盖hashCode()
方法Card
并使其返回相同的值 - 您也应该覆盖equals()
。因为这是HashMap
查找键所引用的对象所依赖的;就目前而言,它是从Object
正在使用的那些方法继承的版本,只有当您使用相同的对象作为键时才会匹配,而您正在创建新的,尽管是“相等”的。