本文介绍了哈希映射自定义类键&&对象保存/加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

现在从事一个项目已经有一段时间了,我遇到了一些似乎并不能一起解决的复杂问题和解决方案.

Been working on a project for a while now and I've come across a few different complications and solutions that don't seem to pan out together.

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

首先,我的哈希图是一个哈希图,其中包含将商品放置(或添加)到世界的时间. place是一个类位置{}",其中包含String world,double x,double y,double z;我遇到的问题是,它不适用于哈希图.我可以使用它存储一个新的哈希键,但是我无法调用以获取其值.相反,使用位置"可以解决此问题(哈希图),并且可以完美地工作.

First, my hashmap is a hashmap containing the time an item was placed (or added) to the world. place is a 'class place {}' containing String world, double x, double y, double z; The problem i've had with this, is that it doesn't work with hashmaps. I can store a new hash key using it, but i cant call to get its value. Using Location instead fixes this problem (hashmap) and works flawlessly.

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());
    }
}

这正常工作.现在,为此目的,必须在禁用和启用插件时保存并重新加载这些数据.为此,我创建了一个具有保存/加载功能的新Java类文件.

This works without error. Now, for the purpose, this data has to be saved and reloaded when the plugin is disabled, and enabled. To do this, i created a new java class file with a save/load feature.

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;
    }
}

我通常会遇到无法序列化"的错误.仅当对象为EMPTY时,使用"implements Serializable"和ois.defaultReadObject()或oos.defaultWriteObject()来检查文件上的序列会导致干净的保存/加载!当它包含数据时,我不断收到"java.io.WriteAbortedException:写异常中止; java.io.NotSerializableException"

I typically get "notserializable" errors. Using 'implements Serializable' and ois.defaultReadObject() or oos.defaultWriteObject() which checks the serial on the file results in a clean save/load only when the object is EMPTY! When it contains data, i constantly get "java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException"

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

This is clearly a problem! One of the recommendations here: ArrayList custom class as HashMap key failed to produce any better results. In fact, creating a custom class was my first issue to begin with >.>

所以我想问题是:

1)使用自定义类作为键(并能正常工作),我必须做些什么改变

1) What would i have to alter to use the custom class as a key (and work properly)

2)为什么无法识别我将其设置为可序列化的类/函数/java类

2) Why doesn't it recognize that i'm setting it as a serializable class/function/java class

3)为什么它适用于空的哈希图,而不适用于填充的哈希图?

3) Why does it work with an empty hashmap, but not with a filled hashmap?

推荐答案

基本上,您需要覆盖place中的hashCode()equals().大概Location已经覆盖了这些方法.

Basically you need to override hashCode() and equals() in place. Presumably Location already overrides these methods.

HashMap所使用的方法是首先非常快速地(使用哈希码)缩小候选键列表的范围,然后(通过调用equals)检查它们的相等性.

Those are the methods that HashMap uses to first narrow down the list of candidate keys very quickly (using the hash code) and then check them for equality (by calling equals).

目前尚不清楚什么是可序列化的问题-我的猜测是,尽管place是可序列化的,但Location却不是.如果您可以发布一个简短但完整的问题来演示该问题,那将会很有帮助. (开始遵循Java命名约定并将您的字段设为私有也是一个好主意...)

It's not clear what the serializable problem is - my guess is that although place is serializable, Location isn't. If you could post a short but complete problem demonstrating the problem, that would really help. (It would also be a good idea to start following Java naming conventions, and making your fields private...)

这是具有哈希代码和相等性的Place类的示例.请注意,为了避免在哈希映射中将其用作键之后的值更改,我将其设置为不可变的-我暂时不知道序列化的效果如何,但希望可以:

Here's an example of the Place class with hash code and equality. Note that I've made it immutable for the sake of avoiding the values changing after it's used as a key in a hash map - I don't know offhand how well that works with serialization, but hopefully it's okay:

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之类的东西.只要在查找它们时,它们的值完全相同,它就可以正常工作.

It's worth noting that this will be comparing Double values for equality, which is almost always a bad idea... but you can't really give a tolerance in something like equals. So long as the values are exactly the same when you come to look them up, it should work fine.

这篇关于哈希映射自定义类键&amp;&amp;对象保存/加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 10:48