level20.lesson10.home03

Подскажите, что делаю не так?

package com.javarush.test.level20.lesson10.home03;

import java.io.Serializable;

/* Найти ошибки
Почему-то при сериализации/десериализации объекта класса B возникают ошибки.
Найдите проблему и исправьте ее.
Класс A не должен реализовывать интерфейсы Serializable и Externalizable.
Сигнатура класса В не содержит ошибку :)
*/
public class Solution implements Serializable {
    private static final long serialVersionUID = 2L;
    public static class A {
        protected String name = "A";

        public A() {
        }

        public A(String name) {
            this.name += name;
        }
    }

    public class B extends A implements Serializable {
        private static final long serialVersionUID = 1L;
        public B(String name) {
            super(name);
            this.name += name;
        }
    }
}


Создавал тестовый psvm, все вродь проходит, но сервер ругается…

19 комментариев

mrtalstyak
у меня все точно так же как у тебя, только serialVersionUID одинаковый и там и там.
nanoezhik
пробовал и с одинаковым, все равно не проходит… Ладно, задачу вродь понял, пока забью, может потом примет…
grobikon
У меня тоже не проходит. Уже по разному отправлял на проверку, но не принимает.
public class Solution implements Serializable{
    private static final long serialVersionUID = 83L;
    public static class A {
        protected String name = "A";
        protected A(){}

        public A(String name) {
            this.name += name;
        }
    }

    public class B extends A implements Serializable {
        private static final long serialVersionUID = 83L;
        public B(String name) {
            super(name);
            this.name += name;
        }
    }
}
grobikon
Кто сдал подскажите что не так.
levka
Присоединяюсь
isaenkovl
Кто не решил, ответьте себе на один вопрос. откуда виртуальная машина сохранит поле name класса B??? С точки зрения стандартного механизма сериализации такого поля нет. То есть нужно явно сохранить поле класса родителя. А это можно сделать используя Externalizable. Но так как сигнатура класса В правильна, то нужно просто добавить два метода и немножко дополнить процесс сериализации… Вот и все
nanoezhik
Спасибо! Помогло…
superz600
УУУУ, наконец-то… спасибо, твой совет помог, валидатор засчитал.

Итого, нужно, оставив класс A static, добиться того, чтобы класс десериализировался с правильными данными. + я расставил константы serialVersionUID
new-Object
  • new-Object
  • 0
  • Комментарий отредактирован 2015-02-23 04:15:38 пользователем new-Object
для тех кто не понимает что за магия там происходит:
static
9) Во время сериализации, также как и transient переменные, статические поля не сериализуются. Действительно, если сохранить любые данные в статическом поле, то после десериализации новый объект будет содержать его первичное (по-умолчанию) значение, например, если статическим полем была переменная типа int, то её значение после десериализации будет равно нулю, если типа float – 0.0, если типа Object – null. Честно говоря, это один из наиболее часто задаваемых вопросов касательно сериализации на собеседованиях по Java. Не храните наиболее важные данные об объекте в статическом поле!
Kiba-From-North
Не совсем корректно на мой взгляд. static в данном случае не при делах. Если ты напишешь
public static class A implements Serializable
и посмотришь в отладчике значения name до и после сериализации, то они будут идентичны. В данной задаче класс А просто не участвует в сериализации. Он лишь является базой объекта B.

Порядок создания объекта B обычном режиме:
1. Вызывается базовый конструктор А с параметром «В». Сначала он инициализирует name значение «A» потом добавляет к ней параметр. Получаем «AB»
2. Вызывается конструктор наследника, и добавляет к name значение параметра еще раз. Получаем «ABB»

Что происходить во время десериализации объекта B:
1. Десириализация сначала создает базовую часть объекта B, вызвая дефолтный конструктор A() котрый инициализирует name значением «A»
2. Десириализация пытается создать все что связано непосредственно с наследником B, но так как ни дефолный механизм ни какие либо другие механизмы не реализованы, этого не проиcходит. И мы получаем десериализованый объект B с name = «A».

Чтобы это забороть, надо управлять сериализаций\десериализацией класса B (наследника). То есть нужно руками сохранить все нужные данные, а потом руками-же их загрузить и ициализировать класс B правильными данными. Как — было в лекциях.

Это лишь часть проблем с данной задачей. Хорошая задача. Кода минимум, а сколько тем затронули. Заставила мозги пошевелиться.
Inquirer
Спасибо!
Толково расписал.
ZemoN
Да, Спасибо!
Дал правильное направление. Кому не понятно — в помощь «Ссылка на сериализацию», а именно «Альтернатива для Externalizable» ;)
Valocop
Кстати, пробовал переопределить сериализацию/десериализацию методами writeObject()/readObject(), протестировал и заметил, что при переопределении не заходит в дефолтный конструктор класса родителя, удалил его и затем еще раз протестировал и все работает, но валидатор не защитал задачу, а вот с дефотным конструктором защитал, может есть какой ответ по этому поводу? или нужно всегда использовать дефолтный конструктор в классе родителе, даже если переопределены методы записи и чтения? буду благодарен за ответ)
prodigy
Красавчик!!!
Pasha_Xa
Объясните кто-нить зачем нам в классе А пустой конструктор?
Treefeed
Pasha_Xa
в доп материалах уже нашёл объяснение, но всё равно спасибо
Morfin
Однако в таком классе обязательно должен быть конструктор по умолчанию, чтобы механизмы сериализации правильно создали объект

Может кто-нибудь объяснить более подробно и понятно, что под этим имеется в виду? Или создание дефолтного конструктора в суперклассе надо просто принять на веру?
s_nikiforov
  • s_nikiforov
  • 0
  • Комментарий отредактирован 2016-10-21 19:42:03 пользователем s_nikiforov
Отличная задача, заставила копнуть глубоко:
1) предок может быть не сериализуемым, но тогда должен быть конструктор по умолчанию
2) если предок не сериализуемый, то данные его полей не пишутся при серализации и инициализируются как при вызове дефолтного конструктора, этот механизм позволяет сериализовать потомков несериализуемых родителей
3) если предок сериализуемый, то все тривиально: он и все его нестатические поля сохраняются при сериализации, вместе с нестатическими полями потомка, конструктор без параметров не обязателен, т.к. ни один конструктор для сериализуемых классов при десериализации НЕ вызывается (ни у потомка, ни у предка)
4) внутренние классы имеют «невидимую» ссылку на объемлющий объект (чтобы иметь доступ к его полям), по этой ссылке механизм сериализации пытается сериализовать объект объемлющего класса,
— если он не сериализуемый, то будет ошибка, фокус как с родительским классом (конструктор без параметров) тут не проходит.
— eсли объемлющий класс сериализуемый, то все его нестатические поля сериализуются и десериализуются вместе с полями внутреннего класса из данных потока (и опять без вызова конструктора!), и эти «внешние» поля будут иметь те же значения как до сериализации, и так же будут доступны десериализованному объекту вложенного класса!
5) если предок не сериализуемый, но нужно сохранить состояние его полей (статических или нестатических), то нужно самостоятельно их писать в поток серализации и читать из него, причем исключительно ПОСЛЕ записи/прочтения самого объекта, можно использовать механизм хук-методов (добавив в своем классе методы writeObject() и readObject()), в которых сначала выполнить стандартные действия сериализации (defaultWriteObject() и defaultReadObject()), а потом добавить запись/чтение всего что стандартными действиями не пишется
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.