механизм сериализации / десериализации - PullRequest
5 голосов
/ 21 декабря 2011

Скажем, у меня есть класс X, который имеет значение поля, то есть

class X implements Serializable {
    private int value;
    // ...
}

Кроме того, здесь есть геттеры и сеттеры, которые здесь не отображаются. Этот класс сериализован. При десериализации конец того же класса имеет поле значения, а спецификатор доступа является открытым. Кроме того, этот класс не имеет геттеров и сеттеров. Итак, мои вопросы:

  1. Сбой десериализации в случае изменения спецификатора доступа поля ИЛИ некоторые или все методы пропадают в классе в конце десериализации?
  2. Каков механизм назначения полей значениям во время десериализации?

Ответы [ 5 ]

5 голосов
/ 21 декабря 2011

Несколько хороших ссылок Обнаружен алгоритм сериализации Java

1) происходит ли десериализация в случае, если спецификатор доступа к полю изменения ИЛИ некоторые или все методы пропадают в классе на конец десериализации?

Сериализация происходит с использованием Reflection

Java Обнаруживает изменения в классе, используя

private static final long serialVersionUID

По умолчанию используется хеш-код. Сериализация создает один хеш-код типа long из следующей информации:

  • Наименование класса и модификаторы

  • Имена любых интерфейсов, которые реализует класс

  • Описания всех методов и конструкторов, кроме частных методов и конструкторов

  • Описания всех полей, кроме частного, статического и частного переходного процесса

Поведение по умолчанию для механизма сериализации - это классическая стратегия «лучше, чем потом сожалеть». Механизм сериализации использует suid, который по умолчанию имеет чрезвычайно чувствительный индекс, чтобы сообщить, когда класс изменился. Если это так, механизм сериализации отказывается создавать экземпляры нового класса, используя данные, которые были сериализованы со старыми классами.

2) каков механизм, с помощью которого полям присваиваются их значения во время десериализации?

3 голосов
/ 21 декабря 2011

Реальные подробности можно прочитать в Спецификации сериализации объектов Java .

Чтобы ответить на ваши вопросы:

  1. Сериализация имеет базовую проверку работоспособности, чтобы увидеть, завершается ли сериализация той же версией класса: член serialVersionUID должен быть равен. Прочтите раздел Уникальные идентификаторы потока , чтобы узнать больше об этом. По сути, это статическое значение, которым вы можете управлять, объявив его в своем классе, или позволить компилятору сгенерировать его для себя. Если компилятор сгенерирует его, ЛЮБОЕ изменение в классе приведет к изменению serialVersionUID и, следовательно, приведет к сбою десериализации, если концы не имеют точно такие же классы. Если вы хотите избежать этого, объявите переменную самостоятельно и обновите ее вручную, если изменение переменных-членов класса делает классы несовместимыми.

  2. Виртуальная машина Java делает здесь много магии, она может напрямую обращаться ко всем внутренним состояниям без необходимости использования получателей (хотя поля, помеченные transient или static, не сериализуются). Кроме того, хотя интерфейс Serializable не определяет какие-либо методы для реализации, существует ряд «магических методов», которые вы можете объявить, чтобы повлиять на процесс сериализации. Прочтите раздел « Метод writeObject » и далее, чтобы узнать больше. Имейте в виду, однако, что вы должны использовать их экономно, поскольку они могут запутать разработчиков программного обеспечения!

2 голосов
/ 21 декабря 2011

Вам не нужно иметь getters / setter для сериализации / десериализации с использованием Java-сериализации, например, проверьте этот код:

public class Main {

    public static class Q implements Serializable {
        private int x;
        public Q() {
            x = 10;
        }
        public void printValue() {
            System.out.println(x);
        }
    }

    public static void main(String[] args) throws Exception {
        Q q = new Q();
        FileOutputStream fos = new FileOutputStream("c:\\temp.out");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(q);
        fos.close();

        FileInputStream fis = new FileInputStream("c:\\temp.out");
        ObjectInputStream oin = new ObjectInputStream(fis);
        Q q2 = (Q)oin.readObject();
        fis.close();
        q2.printValue();

    }
}
2 голосов
/ 21 декабря 2011

Я действительно не знаю, как вы получаете эти результаты, но вы говорите, что не поведение по умолчанию для сериализации. Итак, я думаю, вы используете это неправильно. Вот пример кода:

public class X implements Serializable
{
     private int value;

     public int getValue() { return value; }
}

Здесь процесс сериализации / десериализации:

X x = new X();
x.setValue(4);

ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputSteam(buffer);
oos.writeObject(x);
oos.flush();
oos.close();

ByteArrayInputStream in = new ByteArrayInputStream(buffer.toByteArray());
ObjectInputStream ois = new ObjectInputStream(in);
Object obj = ois.readObject();
if (obj instanceof X)
{
    X readObject = (X) obj;
    System.out.println(readObject.getValue());
}

Возможно, вы использовали Java Reflection , чтобы получить свои результаты. Убедитесь, что вы используете getDeclaredFields(); и getDeclaredMethods(); вместо вариантов без Declared в имени метода.

0 голосов
/ 25 января 2016

Сбой десериализации в случае изменения спецификатора доступа к полю

Нет.

ИЛИ некоторые или все методы пропали без вести в классев конце десериализации?

Да, если только у класса-получателя нет члена serialVersionUID, значение которого равно значению, закодированному в потоке.

чем механизм являетсякаким полям присваиваются их значения во время десериализации?

Слишком широк, но:

  • Отражение и
  • Соответствие имени (а не соответствие по позиции вкласс и стрим).
...