ключ пользовательского класса hashmap && сохранение / загрузка объекта - PullRequest
2 голосов
/ 01 сентября 2011

Некоторое время я работал над проектом, и я столкнулся с несколькими сложностями и решениями, которые, похоже, не сработались.

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 это 'class place {}', содержащий строковый мир, double x, double y, double 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());
    }
}

Это работает без ошибок. Теперь, для этой цели, эти данные должны быть сохранены и загружены, когда плагин отключен и включен. Для этого я создал новый файл класса 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;
    }
}

Обычно я получаю "несериализуемые" ошибки. Использование 'Implements Serializable' и ois.defaultReadObject () или oos.defaultWriteObject (), который проверяет серийный номер в файле, приводит к чистому сохранению / загрузке только тогда, когда объект пуст! Когда он содержит данные, я постоянно получаю «java.io.WriteAbortedException: запись прервана; java.io.NotSerializableException»

Это явно проблема! Вот одна из рекомендаций: Пользовательский класс ArrayList с ключом HashMap не дал лучших результатов. На самом деле, создание собственного класса было моей первой проблемой для начала>.>

Так что я думаю, вопросы:

1) Что бы мне пришлось изменить, чтобы использовать пользовательский класс в качестве ключа (и работать правильно)

2) Почему он не распознает, что я устанавливаю его как сериализуемый класс / функцию / класс Java

3) Почему он работает с пустым hashmap, но не с заполненным hashmap?

1 Ответ

4 голосов
/ 01 сентября 2011

В основном вам нужно переопределить hashCode() и equals() в place. Предположительно Location уже переопределяет эти методы.

Это методы, которые HashMap использует, чтобы сначала очень быстро сузить список ключей-кандидатов (используя хэш-код), а затем проверить их на равенство (вызывая equals).

Непонятно, в чем проблема сериализуемого - я думаю, что, хотя place сериализуем, Location нет. Если бы вы могли опубликовать короткую, но complete проблему, демонстрирующую проблему, это действительно помогло бы (Было бы также неплохо начать следовать соглашениям об именах 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. Пока значения точно одинаковы, когда вы приходите их искать, все должно работать нормально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...