Java readObject и кастинг с наследованием

Это мой первый вопрос, так как до сих пор я всегда находил то, что мне нужно, но на этот раз что-то относительно простое сводит меня с ума. Итак, у меня есть этот класс:

public class QImage {
protected String imagePath;

public QImage() {

}

public QImage(String imgPath) {
    imagePath = imgPath;
}

И тогда:

public class DImage extends QImage implements Serializable {
protected int imageId;

public DImage(String imagePath) {
    imageId = 0;
}

И позже в коде:

private void saveData(String filePath, List<DImage> imap) {
try {

 FileOutputStream fileImap = new FileOutputStream(filePath);
 ObjectOutputStream objectImap = new ObjectOutputStream(fileImap);

    for (DImage image : imap) {
        objectImap.writeObject(image);
    }

И сейчас вроде все в порядке, пока:

public List<DImage> loadData(String filePath) {

    List<DImage> imap = new ArrayList<>();

    try {
        FileInputStream fileImap = new FileInputStream(new File(filePath+"_imap.dat"));
        ObjectInputStream objectImap = new ObjectInputStream(fileImap);

        while (true) {
            try {
                **imap.add((DImage) objectImap.readObject());**
            } catch (EOFException e) {
                break;
            }
        }

Я получаю String imagePath = null. Я уверен, что дело в конструкторах и преобразовании readObject в DImage, но я не знаю, как с этим справиться. Если я создам еще одну строку в DImage, которая не унаследована от QImage, все будет работать нормально.

Редактировать:

Я называю это просто:

    Desc desc = new Desc();
    List<DImage> imagesList = desc.loadData("C:\\collective.xml");

Дело в том, что конструктор по умолчанию вызывается, когда:

imap.add((DImage) objectImap.readObject());

Покажите, где вы звоните loadData

Dioxin 08.06.2018 20:35
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
184
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы получаете imagePath==null, потому что конструктор QImage(String), который устанавливает это поле, никогда не выполняется классом DImage:

public class DImage extends QImage implements Serializable {
protected int imageId;

public DImage(String imagePath) {
    super(imagePath); // <-- you have to call the constructor
    imageId = 0;
}

Редактировать: Кроме того, вы должны сделать так, чтобы ваш класс QImage реализовал Serializable, потому что только поля классов, реализующих этот интерфейс, сохраняются / восстанавливаются (только что проверены).

На самом деле я сам пробовал, и он тоже не работает (поэтому я не упоминал об этом).

mijoypad 08.06.2018 20:33

Если вы не понимаете, что происходит при выполнении, используйте пошаговую отладку при десериализации объекта (ов). В любом случае IMHO чтение и запись объектов через ObjectInpu / OutputStream устарело и очень небезопасно и больше не должно использоваться. Например, лучше использовать Джексона и сериализовать данные только в формате JSON (а не в коде и данных).

Robert 08.06.2018 20:35

@Robert Source о небезопасности объектных потоков Java? И его код не показывает связи между элементом QImage#imagePath и параметром loadData(String filePath), поэтому, хотя он должен по-прежнему делегирует путь к своему супертипу, я не верю, что он показывает что-либо, что предполагает, что эти два связаны (хотя может показаться, что это было бы)

Dioxin 08.06.2018 20:37

Да, imagePath и filePath вообще не связаны. При пошаговом запуске отладчика конструктор QImage по умолчанию (пустой) вызывается при преобразовании readObject в DImage, что меня не удивляет, но я понятия не имею, как его изменить. Его удаление приводит к исключению IOException.

mijoypad 08.06.2018 20:46

Покажите, пожалуйста, где и как вы вызываете loadData, включая объявление и назначение аргументов, которые вы ему передаете.

Dioxin 08.06.2018 20:48

Ага! Большое спасибо. О, я потратил много времени, пытаясь это исправить, и это было всего 2 слова :)

mijoypad 08.06.2018 21:07

Другие вопросы по теме

Есть ли разумная разница между наследованием класса и базовым классом в качестве члена данных в производном классе?
Функция-член, которая возвращает внутри себя двоякий вложенный класс, унаследованный от класса, унаследованного от самого себя
PHP: ведение журнала или отслеживание, когда унаследованный класс вызывает родительскую функцию
ASP.NET Web API 2 переопределить действие маршрута унаследованного атрибута обнаружено несколько действий
Переопределение родительского метода PHP не работает (с использованием пространств имен)
Наследование замыкания Javascript: возможно ли иметь функции с одним и тем же именем в базовом и производном объектах?
Построить подкласс из другого подкласса
Наследование, установщик родительского класса перезаписывает дочернее свойство
Почему этот класс не компилируется?
Swift - Вызов метода подкласса при изменении переменной суперкласса