哈希图自定义类键&&对象保存/加载



我在一个项目上工作了一段时间,我遇到了一些不同的复杂问题和解决方案,这些问题似乎并不能解决。

final public class place implements Serializable {
    private static final long serialVersionUID = -8851896330953573877L;
    String world;
    Double X;
    Double Y;
    Double Z;
}
HashMap<place, Long> blockmap = new HashMap<place, Long>(); // does not work
HashMap<Location, Long> blockmap = new HashMap<Location, Long>(); //works

首先,我的hashmap是一个hashmap,它包含一个项目被放置(或添加)到世界的时间。place是一个'类place{}',包含字符串世界,双x,双y,双z;我有这个问题,是它不与哈希映射工作。我可以使用它存储一个新的哈希键,但我不能调用它来获取它的值。使用Location可以解决这个问题(hashmap),并且可以完美地工作。

public void SetBlock(Block block) {
    Location loc = new Location(null, block.getLocation().getX(),block.getLocation().getY(),block.getLocation().getZ());
    //...
    Long time = (long) (System.currentTimeMillis() / 60000);
    //...
    if (blockmap.containsKey(loc)) {
            blockmap.remove(loc);
            blockmap.put(loc, time);
            //System.out.println("MyLeveler: Block Existed, Updated");
    } else {
            blockmap.put(loc, time);
            //System.out.println("MyLeveler: Block added to " + loc.getX() + ", " + loc.getY() + ", " + loc.getZ());
            //System.out.println("MyLeveler: total blocks saved: " + blockmap.size());
    }
}

这个工作没有错误。现在,为了实现这个目的,必须在插件禁用和启用时保存和重新加载这些数据。为此,我创建了一个带有save/load特性的新java类文件。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SLAPI {
    public static void save(Object obj,String path) throws Exception
    {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
        oos.writeObject(obj);
        oos.flush();
        oos.close();
    }
    public static Object load(String path) throws Exception
    {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
        Object result = ois.readObject();
        ois.close();
        return result;
    }
}

我通常得到"notserializable"错误。使用'implements Serializable'和ois.defaultReadObject()或oos.defaultWriteObject()来检查文件上的序列,只有当对象为空时才会产生干净的保存/加载!当它包含数据时,我总是得到"java.io。WriteAbortedException:写中止;java.io.NotSerializableException "

这显然是个问题!这里的一个建议是:ArrayList自定义类作为HashMap键没有产生任何更好的结果。实际上,创建自定义类是我从>.>

开始的第一个问题。

所以我猜问题是:

1)我必须改变什么使用自定义类作为一个键(并正常工作)

2)为什么它不能识别我将它设置为可序列化的类/函数/java类

3)为什么它工作与一个空的哈希图,而不是与一个填满的哈希图?

基本上你需要在place中覆盖hashCode()equals()。可能Location已经覆盖了这些方法。

这些是HashMap使用的方法,首先非常迅速地缩小候选键列表(使用哈希码),然后检查它们是否相等(通过调用equals)。

不清楚可序列化的问题是什么-我的猜测是,虽然place是可序列化的,Location不是。如果你能发布一个简短但完整的问题来演示这个问题,那将会很有帮助。(这也是一个好主意,开始遵循Java命名约定,并使您的字段私有…)

编辑:下面是Place类的一个示例,带有哈希码和式。请注意,我将其设置为不可变是为了避免在将其用作哈希映射中的键后值发生变化—我不知道这与序列化的效果如何,但希望它是可以的:

public final class Place implements Serializable {
    private static final long serialVersionUID = -8851896330953573877L;
    private final String world;
    // Do you definitely want Double here rather than double?
    private final Double x;
    private final Double y;
    private final Double z;
    public Place(String world, Double x, Double y, Double z) {
        this.world = world;
        this.x = x;
        this.y = y;
        this.z = z;
    }
    @Override public int hashCode() {
        int hash = 17;
        hash = hash * 31 + (world == null ? 0 : world.hashCode());
        hash = hash * 31 + (x == null ? 0 : x.hashCode());
        hash = hash * 31 + (y == null ? 0 : y.hashCode());
        hash = hash * 31 + (z == null ? 0 : z.hashCode());
        return hash;
    }
    @Override public boolean equals(Object other) {
        if (!(other instanceof Place)) {
            return false;
        }
        Place p = (Place) other;
        // Consider using Guava's "Objects" class to make this simpler
        return equalsHelper(world, p.world) &&
               equalsHelper(x, p.x) &&
               equalsHelper(y, p.y) &&
               equalsHelper(z, p.z);
    }
    private static boolean equalsHelper(Object a, Object b) {
        if (a == b) {
            return true;
        }
        if (a == null || b == null) {
            return false;
        }
        return a.equals(b);
    }
    // TODO: Add getters?
}

值得注意的是,这将比较Double值是否相等,这几乎总是一个坏主意…但你不能在equals这样的地方给出一个容忍度。只要值完全相同,当您来查找它们时,它应该可以正常工作

最新更新