Java - map.get不工作,但元素在地图中? [英] Java - map.get don't work, but element is in map?

查看:105
本文介绍了Java - map.get不工作,但元素在地图中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以......所有代码都是:

  //获取矢量... 
SignVector v = ...;

//打印到控制台:[1058,5,820 in flat]
System.out.println(v);

// size:1
System.out.println(size:+ signs.size());

//检查所有元素...
(Entry< SignVector,FakeSign> entry:signs.entrySet())
{
// get key
SignVector key = entry.getKey();

//打印到控制台:[1058,5,820 in flat](YaY!就是这个键!像v)
System.out.println(key);
if(key.equals(v))
{
// print:YaY:
System.out.println(YaY:[1058,5,820 in平]+键);


//所以第二个测试...只需从地图中获取:null
System.out.println(signs.get(v));

为什么返回null?

在JavaDocs中写入:map.get使用 key.equals(k)那么为什么我的代码返回好对象,但是 map.get 返回null?

地图:
private final Map< SignVector,FakeSign> signs = new HashMap<>()





等于方法形式 SignVector for @home user

  @Override 
public boolean equals(Object obj)
{
if(this == obj)
return true;
if(obj == null)
return false;
if(getClass()!= obj.getClass())
return false;
SignVector other =(SignVector)obj;
// w不能为空,所以我跳过
System.out.print(w.getName()+,+ other.w.getName()+,+(w 。.getName()等于(other.w.getName()))); //同样的
if(!w.getName()。equals(other.w.getName()))
return false;
if(x!= other.x)
return false;
if(y!= other.y)
return false;
if(z!= other.z)
return false;
返回true;
}

但是这种方法效果不错,总是返回我想要的 x y z code>和 w 是自定义对象。

解决方案

javadoc有点令人误解,但它依赖于如果你实现equals,你应该实现哈希码以保持一致。正如文档所述:


Collections Framework接口中的许多方法以equals方法的
定义。例如,
containsKey(Object key)方法的规范说:当且仅当此
映射包含键k的映射,以便(key == null?k == null:
key.equals(k))。

本规范不应被解释为暗示使用非空参数键调用Map.containsKey的
将导致
key.equals(k )为任何密钥k调用。

实现对于
是免费的,通过比较两个键的哈希码来实现优化,从而避免了equals调用,例如
。 (
Object.hashCode()规范保证两个具有
不相等散列码的对象不能相等。)

更一般地,实现
$ b

$ b在各种集合框架接口中$ b可以免费获得指定行为的
基础Object方法
的优势。
$ b

让我们来看看 HashMap 的基础实现 get

  314 public V get(Object key){
315 if(key == null)
316返回getForNullKey();
317 int hash = hash(key.hashCode()); (Entry< K,V> e = table [indexFor(hash,table.length)];
319 e!= null;
320 e = e.next){
321对象k;
322 if(e.hash == hash&&((k = e.key)== key || key.equals(k)))
323 return e.value;
324}
325返回null;
326}

你会发现这是使用对象的哈希码来查找可能的条目在表中,然后使用等号确定它必须返回哪个值。由于该条目可能是 null ,因此跳过for循环,并且 get 返回 null < code $。
$ b

SignVector中覆盖 hashCode class与等于一致并且一切正常。


So... all is in code:

// get vector...
SignVector v = ...;

//print to console: [1058, 5, 820 in flat]
System.out.println(v);

//size: 1
System.out.println("size: " + signs.size());

//check all elements...
for (Entry<SignVector, FakeSign> entry : signs.entrySet())
{
    // get key
    SignVector key = entry.getKey();

    //print to console: [1058, 5, 820 in flat] (YaY! it's that key! like v)
    System.out.println(key);
    if (key.equals(v))
    {
        // print: "YaY: " 
        System.out.println("YaY: [1058, 5, 820 in flat]"+key);
    }
}
//So second test... just get it from map: null
System.out.println(signs.get(v));

Why that return null?
In JavaDocs is written that: map.get using key.equals(k) so why my code return good object, but map.get return null?

Map: private final Map<SignVector, FakeSign> signs = new HashMap<>()



Equals method form SignVector for @home user

@Override
public boolean equals(Object obj)
{
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    SignVector other = (SignVector) obj;
    // w can't be null so I skip that
    System.out.print(w.getName() + ", " + other.w.getName() + ", " + (w.getName().equals(other.w.getName()))); // this same
    if (!w.getName().equals(other.w.getName()))
        return false;
    if (x != other.x)
        return false;
    if (y != other.y)
        return false;
    if (z != other.z)
        return false;
    return true;
}

But this method works good, always return that I want, x,y,z is int, and w is custom object.

解决方案

The javadoc is a bit misleading, but it's relying on the fact that if you implement equals, you should also implement hashcode to be consistent. As the doc states:

Many methods in Collections Framework interfaces are defined in terms of the equals method. For example, the specification for the containsKey(Object key) method says: "returns true if and only if this map contains a mapping for a key k such that (key==null ? k==null : key.equals(k))."

This specification should not be construed to imply that invoking Map.containsKey with a non-null argument key will cause key.equals(k) to be invoked for any key k.

Implementations are free to implement optimizations whereby the equals invocation is avoided, for example, by first comparing the hash codes of the two keys. (The Object.hashCode() specification guarantees that two objects with unequal hash codes cannot be equal.)

More generally, implementations of the various Collections Framework interfaces are free to take advantage of the specified behavior of underlying Object methods wherever the implementor deems it appropriate.

Let's take a look a the underlying implementation of get for an HashMap.

314  public V get(Object key) {
315      if (key == null)
316          return getForNullKey();
317      int hash = hash(key.hashCode());
318      for (Entry<K,V> e = table[indexFor(hash, table.length)];
319           e != null;
320           e = e.next) {
321          Object k;
322          if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
323              return e.value;
324      }
325      return null;
326  }

You see that is uses the hashcode of the object to find the possible entries in the table and THEN it uses equals to determine which value it has to return. Since the entry is probably null, the for loop is skipped and get returns null.

Override hashCode in your SignVector class to be consistent with equals and everything should work fine.

这篇关于Java - map.get不工作,但元素在地图中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆