使用HashMaps中的对象作为键

时间:2015-12-12 15:11:32

标签: java hashmap

所以我有一个小问题,我无法解决这个问题。

我需要将一个类对象作为一个键存储在一个映射中,然后由一个新创建的对象查找该映射。我有一个实现Cloneable并覆盖toStringhashCodeequals的类,但似乎该对象是唯一的,无论我如何创建要用作的对象从地图中检索值的键,应该与键匹配的新对象不会。

对象类:

package com.keneti.tekkit.objects;

import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack;

import com.keneti.main.KenetiPrereq;

/** Simple object representing an block by the ID:DATA.
 * 
 * @author Michael Mason */
public class SimpleBlock implements Cloneable {
    protected final int id;
    protected byte data;

    /** Creates a new SimpleBlock object with a data value of zero.
     * 
     * @param id The Block ID. */
    public SimpleBlock(int id) {
        this.id = id;
        this.data = 0;
    }

    /** Creates a new SimpleBlock object.
     * 
     * @param id The Block ID.
     * @param data The block data to set. */
    public SimpleBlock(int id, byte data) {
        this.id = id;
        this.data = data;
    }

    /** Creates a new SimpleBlock object from a {@link Block}.
     * 
     * @param block A bukkit block. */
    public SimpleBlock(Block block) {
        this(block.getTypeId(), block.getData());
    }

    /** Creates a new SimpleBlock object from an {@link ItemStack}.
     * 
     * @param itemStack A bukkit ItemStack. */
    public SimpleBlock(ItemStack itemStack) {
        this(itemStack.getTypeId(), itemStack.getData().getData());
    }

    /** Gets the ID of this block.
     * 
     * @return The ID of this block. */
    public int getId() {
        return id;
    }

    /** Gets the Data for this block.
     * 
     * @return The Data of this block. */
    public byte getData() {
        return data;
    }

    /** Sets the Data for this block.
     * 
     * @param data The Data to set for this block. */
    public void setData(byte data) {
        this.data = data;
    }

    @Override
    public Object clone() {
        try {
            SimpleBlock s = (SimpleBlock) super.clone();
            return s;
        }
        catch (CloneNotSupportedException e) {
            KenetiPrereq.journal.fine("CloneNotSupportedException: SimpleBlock " + this.toString());
            throw new Error(e);
        }
    }

    @Override
    public String toString() {
        return "{SimpleBlock:" + this.id + ":" + this.data + "}";
    }

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

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof SimpleBlock) return (this.id == ((SimpleBlock) obj).id) && (this.data == ((SimpleBlock) obj).data);
        if (obj instanceof ItemStack) return (this.id == ((ItemStack) obj).getTypeId()) && (this.data == ((ItemStack) obj).getData().getData());
        if (obj instanceof Block) return (this.id == ((Block) obj).getTypeId()) && (this.data == ((Block) obj).getData());
        return false;
    }

}

运行代码

// The Map holding the value
private LinkedHashMap<SimpleBlock, LinkedList<Location>> locationsmap;

// I create the SimpleBlock object like this
SimpleBlock sb = new SimpleBlock(758, (byte) 14);

// I add the locations with the SimpleBlock object as the key.
locationsmap.put(sb, locations);

后来,在另一个班级:

// so after getting the map in a local variable..
LinkedList<Location> locations = locationsMap.get(new SimpleBlock(758, (byte) 14));

当我尝试使用相同的创建数据获取对象时,它没有在地图中看到对象(虽然我在步进代码时看到它,但它肯定在那里)

我的问题是,这目前的工作原理是什么?我确定我已经完成了使对象相等的必要步骤?

提前谢谢你:D

1 个答案:

答案 0 :(得分:1)

equals和hashcode的实现不满足所需的合同(参见http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals%28java.lang.Object%29)。

简而言之,SimpleBlock对象可以等于另一个对象,但具有不同的哈希码

  

如果两个对象根据equals(Object)方法相等,那么   必须在两个对象中的每一个上调用hashCode方法   相同的整数结果。

解决这个问题,我认为你可以解决问题。

编辑:另外,使用库来构建equals和hashcode方法会更容易:https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/builder/EqualsBuilder.htmlhttps://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/builder/HashCodeBuilder.html