Каково использование идентификатора сериализации в создании пользовательских исключений и классов Servlet? [dубликат]

Я тоже это вижу. Проблема началась после обновления nvidia. Пока я откажусь от этого, я скажу вам единственное найденное решение

Run

ps aux | grep suspend

вы должны увидеть процесс приостановки root. Затем отключите этот процесс:

sudo kill -9 xxxx

, где xxxx - номер задания.

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

2498
задан 18 March 2015 в 02:44

19 ответов

serialVersionUID облегчает управление версиями сериализованных данных. Его значение хранится с данными при сериализации. При де-сериализации одна и та же версия проверяется, как сериализованные данные соответствуют текущему коду.

Если вы хотите изменить свои данные, вы обычно начинаете с serialVersionUID из 0 и ударяете его с каждым структурным изменением в свой класс, который изменяет сериализованные данные (добавление или удаление непереходных полей) ,

Встроенный механизм де-сериализации (in.defaultReadObject()) откажется от де-сериализации из старых версий данных. Но если вы хотите, чтобы вы могли определить свою собственную функцию readObject (), которая может считывать старые данные. Этот пользовательский код может затем проверить serialVersionUID, чтобы узнать, в какой версии находятся данные, и решить, как де-сериализовать его. Этот метод управления версиями полезен, если вы храните сериализованные данные, которые выживают в нескольких версиях вашего кода.

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

В этом случае вы не заинтересованы в поддержании обратной совместимости. Вам нужно только убедиться, что базы кода, которые действительно обмениваются сообщениями, имеют одинаковые версии соответствующих классов. Чтобы облегчить такую ​​проверку, вы должны поддерживать serialVersionUID так же, как и раньше, и не забывать обновлять его при внесении изменений в свои классы.

Если вы забыли обновить поле, вы можете получить две разные версии класса с разной структурой, но с тем же serialVersionUID. Если это произойдет, механизм по умолчанию (in.defaultReadObject()) не обнаружит разницы и попытается дезацинировать несовместимые данные. Теперь у вас может возникнуть критическая ошибка времени выполнения или молчащий сбой (пустые поля). Эти типы ошибок могут быть трудно найти.

Итак, чтобы помочь этому пользователю, платформа Java предлагает вам выбор, не устанавливающий вручную serialVersionUID. Вместо этого хэш структуры класса будет генерироваться во время компиляции и использоваться как id. Этот механизм будет гарантировать, что у вас никогда не будет разных структур классов с одним и тем же идентификатором, и поэтому вы не получите эти сбои с последовательной сериализацией с жесткими трассировками, упомянутые выше.

Но есть задняя сторона авто -генерированная стратегия id. А именно, что генерируемые идентификаторы для одного и того же класса могут отличаться между компиляторами (как упоминал выше, Джон Скит). Поэтому, если вы передаете сериализованные данные между кодом, скомпилированным с разными компиляторами, рекомендуется поддерживать идентификаторы вручную в любом случае.

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

96
ответ дан 15 August 2018 в 16:58
  • 1
    Добавление или удаление непереходных полей не делает сериализацию класса несовместимой. Поэтому нет никаких оснований для того, чтобы «наброситься» на такие изменения. – user207421 7 February 2014 в 07:05
  • 2
    @EJP: А? Добавление данных, безусловно, изменяет данные сериализации в моем мире. – Alexander Torstling 8 February 2014 в 01:12
  • 3
    @AlexanderTorstling Прочитайте то, что я написал. Я не сказал, что он не «меняет данные сериализации». Я сказал, что «не делает сериализацию класса несовместимой». Это не одно и то же. Вам необходимо прочитать главу «Версии» в разделе «Сериализация объектов». – user207421 21 May 2014 в 02:27
  • 4
    @EJP: Я понимаю, что добавление непереходного поля необязательно означает, что вы делаете сериализацию класса несовместимой, но это структурное изменение, которое изменяет сериализованные данные, и вы, как правило, хотите поднять версию при этом, если только вы совместите обратную совместимость, о которой я также объяснил позже в сообщении. Какова ваша точка зрения? – Alexander Torstling 21 May 2014 в 11:42

Я обычно использую serialVersionUID в одном контексте: когда я знаю, что он покинет контекст виртуальной машины Java.

Я бы это знал, когда я использовал ObjectInputStream и ObjectOutputStream для своего приложения, или если я знаю, что используемая библиотека / фрейм будет использоваться. SerialVersionID гарантирует, что разные виртуальные машины Java разных версий или поставщики будут взаимодействовать правильно или если они будут храниться и извлекаться вне VM, например HttpSession, данные сеанса могут оставаться даже во время перезагрузки и обновления сервера приложений.

Для всех других случаев я использую

@SuppressWarnings("serial")

, так как большую часть времени по умолчанию serialVersionUID является достаточным. Это включает в себя Exception, HttpServlet.

13
ответ дан 15 August 2018 в 16:58
  • 1
    Он не включает HttpServlet в контейнерах, где они могут быть заменены, или Exception в RMI, например. – user207421 21 May 2014 в 02:36

Данные поля представляют некоторую информацию, хранящуюся в классе. Класс реализует интерфейс Serializable, поэтому eclipse автоматически предлагается объявить поле serialVersionUID. Давайте начнем с установленного значения 1.

Если вы не хотите, чтобы это предупреждение появилось, используйте это:

@SuppressWarnings("serial")
11
ответ дан 15 August 2018 в 16:58

Каждый раз, когда объект сериализуется, объект имеет штамп с номером идентификатора версии для класса объекта. Этот идентификатор называется serialVersionUID и вычисляется на основе информации о структуре класса. Предположим, что вы создали класс Employee, и у него есть версия id 333 (назначенная JVM). Теперь, когда вы будете сериализовать объект этого класса (предположим объект Employee), JVM присваивает ему UID как # 333.

Рассмотрите ситуацию - в будущем вам нужно отредактировать или изменить свой класс, и в этом случае, когда вы его измените, JVM назначит ему новый UID (предположим # 444). Теперь, когда вы пытаетесь десериализовать объект employee, JVM будет сравнивать идентификатор версии объекта (объекта Employee) объекта сериализованного объекта (# 333) с классом класса i.e # 444 (поскольку он был изменен). При сравнении JVM найдет и версию UID разных, и, следовательно, Deserialization не удастся. Следовательно, если serialVersionID для каждого класса определяется самим программистом. Он будет таким же, даже если класс будет развиваться в будущем, и поэтому JVM всегда найдет, что класс совместим с сериализованным объектом, даже если класс изменен. Для получения дополнительной информации вы можете обратиться к главе 14 главы HEAD FIRST JAVA.

4
ответ дан 15 August 2018 в 16:58
  • 1
    Каждый раз, когда класс объекта объекта сериализуется, передается serialVersionUID. Он не отправляется с каждым объектом. – user207421 25 November 2017 в 13:00

Этот вопрос очень хорошо документирован в «Эффективной Java» Джошуа Блоха. Очень хорошая книга и должна читать. Ниже я расскажу о некоторых из следующих причин:

В среде выполнения сериализации появляется номер под названием Serial для каждого сериализуемого класса. Этот номер называется serialVersionUID. Теперь за этим числом есть математика, и она выходит на основе полей / методов, определенных в классе. Для того же класса одна и та же версия генерируется каждый раз. Этот номер используется во время десериализации, чтобы убедиться, что отправитель и получатель сериализованного объекта загружают классы для этого объекта, которые совместимы с сериализацией. Если приемник загрузил класс для объекта с другим идентификатором serialVersionUID, чем класс соответствующего класса отправителя, то десериализация приведет к InvalidClassException.

Если класс сериализуем, вы также можете объявить свой собственный serialVersionUID явно объявив поле с именем «serialVersionUID», которое должно быть статическим, окончательным и длинным. Большинство IDE, таких как Eclipse, помогают генерировать эту длинную строку.

4
ответ дан 15 August 2018 в 16:58

Не беспокойтесь, расчет по умолчанию действительно хорош и достаточен для 99,9999% случаев. И если у вас возникнут проблемы, вы можете - как уже было сказано, ввести UID в качестве необходимости (что маловероятно)

18
ответ дан 15 August 2018 в 16:58
  • 1
    Мусор. Он адекватен в случае, когда класс не изменился. У вас нет доказательств для поддержки «99,9999%». – user207421 22 March 2018 в 14:30

Сначала мне нужно объяснить сериализацию. Сериализация позволяет преобразовать объект в поток, для отправки этого объекта по сети ИЛИ Сохранить в файл ИЛИ сохранить в БД для использования букв.

Сериализация .

Объект сериализуется, только если его класс или его суперкласс реализует интерфейс Serializable. Объект сериализуем (сам реализует интерфейс Serializable), даже если его суперкласс не является. Однако первый суперкласс в иерархии сериализуемого класса, который не реализует интерфейс Serializable, ДОЛЖЕН иметь конструктор no-arg. Если это нарушено, readObject () создаст исключение java.io.InvalidClassException во время выполнения. Все примитивные типы являются сериализуемыми. Временные поля (с переходным модификатором) НЕ сериализуются (то есть не сохраняются или не восстанавливаются). Класс, который реализует Serializable, должен отмечать переходные поля классов, которые не поддерживают сериализацию (например, поток файлов). Статические поля (со статическим модификатором) не сериализованы.

Когда объект сериализован, JAVA Runtime связывает номер серийной версии, который называется serialVersionID.

Где нам нужен serialVersionID: во время десериализации, чтобы убедиться, что отправитель и получатель совместимы в отношении сериализации. Если приемник загрузил класс с помощью другого serialVersionID, то десериализация закончится InvalidClassCastException. Сериализуемый класс может объявить свой собственный serialVersionUID явно, объявив поле с именем «serialVersionUID», которое должно быть статическим, окончательным и длинным:.

Давайте попробуем это с примером.

import java.io.Serializable;    
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String empname;
private byte empage;

public String getEmpName() {
    return name;
}
public void setEmpName(String empname) {
    this.empname = empname;
}
public byte getEmpAge() {
    return empage;
}
public void setEmpAge(byte empage) {
    this.empage = empage;
}

public String whoIsThis() {
    StringBuffer employee = new StringBuffer();
    employee.append(getEmpName()).append(" is ).append(getEmpAge()).append("
years old  "));
    return employee.toString();
}
}

Создать объект Serialize

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Writer {
public static void main(String[] args) throws IOException {
    Employee employee = new Employee();
    employee.setEmpName("Jagdish");
    employee.setEmpAge((byte) 30);

    FileOutputStream fout = new 
FileOutputStream("/users/Jagdish.vala/employee.obj");
    ObjectOutputStream oos = new ObjectOutputStream(fout);
    oos.writeObject(employee);
    oos.close();
    System.out.println("Process complete");
}
}

Deserializ объект

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Reader {
public static void main(String[] args) throws ClassNotFoundException, 
IOException {
    Employee employee = new Employee();
    FileInputStream fin = new 
    FileInputStream("/users/Jagdish.vala/employee.obj");
    ObjectInputStream ois = new ObjectInputStream(fin);
    employee = (Employee) ois.readObject();
    ois.close();
    System.out.println(employee.whoIsThis());
 }
}    

ПРИМЕЧАНИЕ. Теперь измените serialVersionUID класса Employee и сохраните:

private static final long serialVersionUID = **4L**;

И выполните класс Reader. Не выполнять класс Writer, и вы получите исключение.

Exception in thread "main" java.io.InvalidClassException: 
com.jagdish.vala.java.serialVersion.Employee; local class incompatible: 
stream classdesc serialVersionUID = 1, local class serialVersionUID = 4
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.krishantha.sample.java.serialVersion.Reader.main(Reader.java:14)
11
ответ дан 15 August 2018 в 16:58
Что такое serialVersionUID и почему я должен его использовать?

SerialVersionUID является уникальным идентификатором для каждого класса, JVM использует его для сравнения версий класса, гарантирующих, что один и тот же класс использовался во время сериализации, загружается во время десериализации.

Указание одного дает больше контроля, хотя JVM создает его, если вы не укажете. Созданное значение может различаться между разными компиляторами. Кроме того, иногда вы просто хотите по какой-то причине запретить десериализацию старых сериализованных объектов [backward incompatibility], и в этом случае вам просто нужно изменить serialVersionUID.

javadocs для Serializable говорят:

Что такое serialVersionUID и зачем его использовать?

по умолчанию serialVersionUID вычисление очень чувствительно к деталям класса, которое может варьироваться в зависимости от реализаций компилятора и может таким образом привести к неожиданным InvalidClassException s во время десериализации.

javadocs для Serializable говорят .

62
ответ дан 15 August 2018 в 16:58
  • 1
    @Vinothbabu, но serialVersionUID статичен, поэтому статические переменные не могут быть сериализованы. то как же jvm проверит версию, не зная, какая версия десериализующего объекта – Kranthi Sama 16 June 2014 в 16:06
  • 2
    Единственное, что не упомянуто в этом ответе, это то, что вы можете вызвать непреднамеренные последствия, слепо в том числе serialVersionUID, не зная почему. Комментарий Тома Андерсона на ответ MetroidFan2002 обращается к этому: «Я бы сказал, что если вы не используете сериализацию для постоянного хранения, вы должны использовать @SuppressWarnings, а не добавлять значение. Он загромождает класс меньше, и он сохраняет способность механизма serialVersionUID защищать вас от несовместимых изменений. & Quot; – Kirby 17 June 2014 в 21:30
  • 3
    serialVersionUID - не - уникальный идентификатор для каждого класса. Это полное имя класса. Это индикатор версии . – user207421 9 June 2015 в 07:17

Я не могу упустить эту возможность, чтобы подключить книгу Джоша Блоха «Эффективная Java» (2-е издание). Глава 11 является незаменимым ресурсом для сериализации Java.

Per Josh, автоматически созданный UID создается на основе имени класса, реализованных интерфейсов и всех открытых и защищенных членов. Изменение любого из них каким-либо образом изменит значение serialVersionUID. Поэтому вам не нужно возиться с ними, только если вы уверены, что не более чем одна версия класса будет когда-либо сериализована (либо через процессы, либо позже из хранилища).

Если вы игнорируете их на данный момент и позже обнаружите, что вам нужно каким-то образом изменить класс, но поддерживать совместимость с старой версией этого класса, вы можете использовать селектор JDK для генерации serialVersionUID в старом классе и явно установите это на новый класс. (В зависимости от ваших изменений вам может потребоваться также реализовать пользовательскую сериализацию, добавив методы writeObject и readObject - см. [F5] javadoc или вышеупомянутую главу 11.)

265
ответ дан 15 August 2018 в 16:58
  • 1
    Таким образом, можно было бы столкнуться с SerializableVersionUID, если бы кто-то беспокоился о совместимости с старыми версиями класса? – Ziggy 1 January 2009 в 11:28
  • 2
    Yup, в случае, если новая версия изменяет любой защищенный публичный элемент, значение SerializableVersionUID по умолчанию будет отличаться и будет вызывать InvalidClassExceptions. – Chander Shivdasani 14 January 2012 в 01:49
  • 3
    class Name, реализованные интерфейсы, все общедоступные и защищенные методы, ВСЕ переменные экземпляра. – Achow 1 March 2013 в 10:38
  • 4
    Стоит отметить, что Джошуа Блох советует, что для каждого класса Serializable стоит указать серийную версию uid. Цитата из главы 11: Независимо от того, какую сериализованную форму вы выберете, объявите явный идентификатор серийной версии в каждом сериализуемом классе, который вы пишете. Это устраняет UID последовательной версии как потенциальный источник несовместимости (пункт 74). Существует также небольшое преимущество в производительности. Если не задан UID с последовательной версией, для генерации одного во время выполнения требуется дорогостоящее вычисление. – Ashutosh Jindal 8 July 2014 в 18:25

Вы можете сказать Eclipse игнорировать эти предупреждения serialVersionUID:

Окно> Настройки> Java> Компилятор> Ошибки / предупреждения> Проблемы с программированием

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

Потенциальные проблемы программирования: Возможное случайное логическое назначение Потенциальные проблемы программирования: Доступ к нулевому указателю Необязательный код: Локальная переменная никогда не читается. Ненужный код: избыточная проверка нуля. Ненужный код: ненужный листинг или «экземпляр»

и многие другие.

124
ответ дан 15 August 2018 в 16:58
  • 1
    но только потому, что исходный плакат, похоже, не сериализует что-либо. Если бы плакат сказал «я сериализую эту вещь и ...» то вместо этого вы получите голосование: P – John Gardner 13 November 2008 в 05:28
  • 2
    Правда - я предполагал, что вопросник просто не хотел, чтобы его предупреждали – matt b 13 November 2008 в 06:52
  • 3
    @Gardner - & gt; согласовано! Но вопрошающий также хочет знать, почему он не хочет быть предупрежденным. – Ziggy 1 January 2009 в 11:29
  • 4
    Вопрос, по-видимому, заботится о том, почему должен быть UID. Поэтому просто говорить ему, чтобы игнорировать предупреждение, должно быть опущено. – cinqS 18 April 2017 в 06:31

Если вы сериализуете только потому, что вам нужно сериализовать для реализации (кого волнует, если вы сериализуете для HTTPSession, например ... если он хранится или нет, вам, вероятно, не нужно де-сериализовать form object), тогда вы можете игнорировать это.

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

В большинстве случаев вы, вероятно, не будете использовать сериализацию напрямую. Если это так, создайте стандартный сериализуемый uid, щелкнув опцию быстрого исправления и не беспокойтесь об этом.

416
ответ дан 15 August 2018 в 16:58
  • 1
    Я бы сказал, что если вы не используете сериализацию для постоянного хранения, вы должны использовать @SuppressWarnings, а не добавлять значение. Он загромождает класс меньше, и он сохраняет изобилие механизма serialVersionUID, чтобы защитить вас от несовместимых изменений. – Tom Anderson 24 April 2011 в 15:43
  • 2
    @ MetroidFan2002: Я думаю, что пункт TomAnderson serialVersionUID, защищающий вас от несовместимых изменений, действителен. Использование @SuppressWarnings документов лучше, если вы не хотите использовать класс для постоянного хранения. – AbdullahC 30 December 2011 в 20:32
  • 3
    «Вы должны увеличить его, если текущая версия вашего класса не обратно совместима с предыдущей версией: & quot; Сначала вы должны изучить обширную поддержку версий Serialization для версий, (a) обеспечить, чтобы класс действительно стал несовместимым по сериализации, что по спецификации довольно сложно достичь; (b) попробовать такую ​​схему, как пользовательские методы read / writeObject (), методы readResolve / writeReplace (), объявления serializableFields и т. д., чтобы убедиться, что поток остается совместимым. Изменение фактического serialVersionUID - последнее средство, совет отчаяния. – user207421 12 December 2012 в 06:59
  • 4
    Приращение @EJP serialVersionUID входит в картину, когда исходный автор класса ввел явно. Я бы сказал, jvm сгенерированный серийный идентификатор, должно быть хорошо. это лучший ответ , который я видел при сериализации. – overexchange 24 December 2014 в 19:39

SerialVersionUID используется для управления версиями объекта. вы также можете указать serialVersionUID в своем файле класса. Следствием не указания serialVersionUID является то, что когда вы добавляете или изменяете любое поле в классе, тогда уже сериализованный класс не сможет восстановить, потому что serialVersionUID, сгенерированный для нового класса и для старого сериализованного объекта, будет другим. Процесс сериализации Java основан на правильном serialVersionUID для восстановления состояния сериализованного объекта и бросает java.io.InvalidClassException в случае несоответствия serialVersionUID

Подробнее: http://javarevisited.blogspot.com/2011/04/top -10-Java-сериализации-interview.html # ixzz3VQxnpOPZ

10
ответ дан 15 August 2018 в 16:58

Если вам никогда не понадобится сериализовать ваши объекты в массив байтов и отправить / сохранить их, вам не нужно беспокоиться об этом. Если да, то вы должны учитывать свой serialVersionUID, поскольку десериализатор объекта будет соответствовать его версии объекта, который имеет его загрузчик классов. Подробнее об этом читайте в спецификации языка Java.

30
ответ дан 15 August 2018 в 16:58
  • 1
    Если вы не собираетесь сериализовать объекты, почему они являются Serializable? – erickson 13 November 2008 в 09:34
  • 2
    @erickson - родительский класс может быть сериализуемым, скажем, ArrayList, но вы хотите, чтобы ваш собственный объект (скажем, измененный список массивов) использовал его в качестве базы, но никогда не собирался сериализовать созданную коллекцию. – MetroidFan2002 30 March 2009 в 19:12
  • 3
    Он нигде не упоминается в Спецификации языка Java. Он упоминается в Спецификации Версии Объекта. – user207421 7 February 2014 в 07:10
  • 4
    Вот ссылка на спецификацию версии Java для Java 8 . – Basil Bourque 3 November 2014 в 08:12

Если вы получите это предупреждение в классе, о котором вы никогда не думали о сериализации, и о том, что вы не заявили о себе implements Serializable, это часто происходит потому, что вы унаследовали от суперкласса, который реализует Serializable. Часто после этого было бы лучше делегировать такой объект вместо использования наследования.

Итак, вместо

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

do

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

и в соответствующих методах вызовите myList.foo() вместо this.foo() (или super.foo()). (Это не подходит во всех случаях, но все же довольно часто.)

Я часто вижу людей, расширяющих JFrame или таких, когда им действительно нужно только делегировать это. (Это также помогает для автозаполнения в среде IDE, поскольку JFrame имеет сотни методов, которые вам не нужны, когда вы хотите называть свои собственные в своем классе.)

В одном случае, когда предупреждение (или serialVersionUID) неизбежно, когда вы расширяетесь из AbstractAction, обычно в анонимном классе, добавляя только метод actionPerformed. Я думаю, что в этом случае не должно быть предупреждения (поскольку вы, как правило, не можете достоверно сериализовать и десериализовать такие анонимные классы в любом случае в разных версиях вашего класса), но я не уверен, как компилятор смог бы это распознать.

33
ответ дан 15 August 2018 в 16:58
  • 1
    Я думаю, что вы правы, что композиция в отношении затенения имеет больше смысла, особенно когда вы обсуждаете такие классы, как ArrayList. Тем не менее, многие структуры требуют от людей расширения от абстрактных суперклассов, которые могут быть сериализуемыми (например, класса ActionForm от Struts 1.2 или Saxon ExtensionFunctionDefinition), и в этом случае это решение неосуществимо. Я думаю, что вы правы, было бы неплохо, если бы предупреждение было проигнорировано в некоторых случаях (например, если вы распространялись из абстрактного сериализуемого класса) – piepera 7 December 2011 в 21:20
  • 2
    Разумеется, если вы добавите класс в качестве члена, а не наследуете его, вам придется написать метод обертки для метода КАЖДОГО класса-члена, который вы хотели использовать, что сделало бы его невозможным в большом количестве ситуаций. . Если у java есть функция, аналогичная функции perl __AUTOLOAD, о которой я не знаю. – M_M 20 August 2012 в 03:15
  • 3
    @M_M: Когда вы делегируете множество методов вашему обернутому объекту, конечно, было бы нецелесообразно использовать делегирование. Но я полагаю, что этот случай является признаком ошибки дизайна - пользователям вашего класса (например, «MainGui») не нужно будет вызывать множество методов обернутого объекта (например, JFrame). – Paŭlo Ebermann 20 August 2012 в 13:09
  • 4
    То, что мне не нравится в делегировании, - это необходимость иметь ссылку на делегата. И каждая ссылка означает больше памяти. Поправьте меня если я ошибаюсь. Если мне нужен CustomizedArrayList из 100 объектов, это не имеет большого значения, но если мне понадобится сотни CustomizdeArrayLists из нескольких объектов, то использование памяти значительно возрастет. – WVrock 29 November 2014 в 11:14
  • 5
    Throwable является сериализуемым, и только Throwable может быть сбрасываемым, поэтому невозможно определить исключение, которое не является сериализуемым. Делегирование невозможно. – Phil 13 April 2017 в 05:59

Зачем использовать SerialVersionUID внутри класса Serializable в Java?

Во время работы serialization среда выполнения Java создает номер версии для класса, так что она может де-сериализовать ее позже. Этот номер версии известен как SerialVersionUID в Java.

SerialVersionUID используется для версии сериализованных данных. Вы можете только де-сериализовать класс, если он SerialVersionUID соответствует сериализованному экземпляру. Когда мы не объявляем SerialVersionUID в нашем классе, среда выполнения Java генерирует его для нас, но не рекомендуется. Рекомендуется исключить SerialVersionUID как переменную private static final long, чтобы избежать механизма по умолчанию.

Когда вы объявляете класс как Serializable, реализуя интерфейс-маркер java.io.Serializable, Java runtime сохраняет экземпляр этого класса на диск, используя механизм Serialization по умолчанию, если вы не настроили процесс, используя Externalizable интерфейс

см. также Почему использование SerialVersionUID внутри класса Serializable в Java

Код: Зачем использовать SerialVersionUID внутри класса Serializable в Java

7
ответ дан 15 August 2018 в 16:58

Если вы хотите изменить огромное количество классов, в которых не было установленного параметра serialVersionUID, в то же время поддерживая совместимость со старыми классами, такие инструменты, как IntelliJ Idea, Eclipse, сокращаются по мере генерации случайных чисел и не работают на кучу файлов за один раз. Я прихожу к следующему сценарию bash (я прошу прощения за пользователей Windows, подумайте о покупке Mac или конвертируйте в Linux), чтобы облегчить исправление проблемы serialVersionUID:

base_dir=$(pwd)                                                                  
src_dir=$base_dir/src/main/java                                                  
ic_api_cp=$base_dir/target/classes                                               

while read f                                                                     
do                                                                               
    clazz=${f//\//.}                                                             
    clazz=${clazz/%.java/}                                                       
    seruidstr=$(serialver -classpath $ic_api_cp $clazz | cut -d ':' -f 2 | sed -e 's/^\s\+//')
    perl -ni.bak -e "print $_; printf qq{%s\n}, q{    private $seruidstr} if /public class/" $src_dir/$f
done

вы сохраняете этот скрипт, скажем, add_serialVersionUID.sh вам ~ / bin. Затем запустите его в корневой директории вашего проекта Maven или Gradle, например:

add_serialVersionUID.sh < myJavaToAmend.lst

Этот .lst включает в себя список java-файлов для добавления serialVersionUID в следующем формате:

com/abc/ic/api/model/domain/item/BizOrderTransDO.java
com/abc/ic/api/model/domain/item/CardPassFeature.java
com/abc/ic/api/model/domain/item/CategoryFeature.java
com/abc/ic/api/model/domain/item/GoodsFeature.java
com/abc/ic/api/model/domain/item/ItemFeature.java
com/abc/ic/api/model/domain/item/ItemPicUrls.java
com/abc/ic/api/model/domain/item/ItemSkuDO.java
com/abc/ic/api/model/domain/serve/ServeCategoryFeature.java
com/abc/ic/api/model/domain/serve/ServeFeature.java
com/abc/ic/api/model/param/depot/DepotItemDTO.java
com/abc/ic/api/model/param/depot/DepotItemQueryDTO.java
com/abc/ic/api/model/param/depot/InDepotDTO.java
com/abc/ic/api/model/param/depot/OutDepotDTO.java

Этот скрипт использует инструмент JDK serialVer под капотом. Поэтому убедитесь, что ваш JAVA_HOME / bin в PATH.

5
ответ дан 15 August 2018 в 16:58
  • 1
    Дает мне идею: всегда обновляйте серийную версию uid с помощью такого инструмента, никогда вручную, перед выпуском - таким образом, вы избегаете забывать внести изменения в класс, серийная версия которого uid должна была измениться из-за фактического несовместимые изменения. Следить за этим вручную очень сложно. – Ignazio 17 March 2016 в 22:05

Как пример, когда отсутствующий serialVersionUID может вызвать проблему:

Я работаю над этим приложением Java EE, которое состоит из веб-модуля, который использует модуль EJB. Веб-модуль удаляет модуль EJB удаленно и передает POJO, который реализует Serializable в качестве аргумента.

Этот класс POJO's был упакован внутри банка EJB и внутри собственной банки в WEB-INF / lib веб-модуля. Они - фактически тот же самый класс, но когда я упаковываю модуль EJB, я распаковываю этот баннер POJO, чтобы упаковать его вместе с модулем EJB.

Вызов EJB был неудачным с Исключением ниже, потому что Я не объявил его serialVersionUID:

Caused by: java.io.IOException: Mismatched serialization UIDs : Source
 (Rep.
 IDRMI:com.hordine.pedra.softbudget.domain.Budget:5CF7CE11E6810A36:04A3FEBED5DA4588)
 = 04A3FEBED5DA4588 whereas Target (Rep. ID RMI:com.hordine.pedra.softbudget.domain.Budget:7AF5ED7A7CFDFF31:6227F23FA74A9A52)
 = 6227F23FA74A9A52
17
ответ дан 15 August 2018 в 16:58

Было бы неплохо, если CheckStyle мог убедиться, что serialVersionUID для класса, который реализует Serializable, имеет хорошее значение, то есть он соответствует тому, что будет генерировать генератор идентификаторов серийной версии. Если у вас есть проект с большим количеством сериализуемых DTO, например, помня, что нужно удалить существующий serialVersionUID и восстановить его, это боль, и в настоящее время единственный способ (который я знаю) проверить это - это регенерировать для каждого класса и сравнить с Старый. Это очень больно.

10
ответ дан 15 August 2018 в 16:58
  • 1
    Если вы установите serialVersionUID всегда на то же значение, которое генерирует генератор, вам это совсем не нужно. В конце концов, его raison d'être должен оставаться таким же после изменений, когда класс все еще совместим. – Paŭlo Ebermann 20 February 2011 в 06:04
  • 2
    Люди, которые действительно используют Сериализацию для целей хранения / поиска, обычно устанавливают для параметра serialVersionUID значение 1. Если более новая версия класса несовместима, но по-прежнему требует обработки старых данных, вы увеличиваете номер версии и добавляете специальный код для работы со старыми форматами. Я плачу каждый раз, когда вижу serialVersionUID больше, чем 1 цифру, либо потому, что это случайное число (бесполезно), либо потому, что класс, по-видимому, должен иметь дело с более чем 10 различными версиями. – john16384 10 February 2018 в 15:11

Чтобы понять значение поля serialVersionUID, нужно понимать, как работает сериализация / десериализация.

Когда объект класса Serializable сериализуется, Java Runtime связывает серийный номер версии (называемый serialVersionUID) с этим сериализованным объект. В то время, когда вы десериализируете этот сериализованный объект, Java Runtime соответствует serialVersionUID сериализованного объекта с serialVersionUID этого класса. Если оба они равны, то только он продолжается с дальнейшим процессом десериализации else, выдает InvalidClassException.

Итак, мы заключаем, что для успешного завершения процесса Serialization / Deserialization serialVersionUID сериализованного объекта должен быть эквивалентен serialVersionUID класса , В случае, если программист явно указывает значение serialVersionUID в программе, то такое же значение будет связано с сериализованным объектом и классом, независимо от платформы сериализации и десериализации (например, сериализация может выполняться на платформе, например, с помощью окна или MS JVM и Deserialization могут быть на другой платформе Linux с использованием Zing JVM).

Но если serialVersionUID не указан программистом, то при выполнении Serialization \ DeSerialization любого объекта среда выполнения Java использует свой собственный алгоритм для вычисления Это. Этот алгоритм вычисления serialVersionUID варьируется от одной JRE к другой. Также возможно, что среда, в которой объект сериализуется, использует одну JRE (например: SUN JVM) и среду, в которой происходит десериализация, используется Linux Jvm (zing). В таких случаях serialVersionUID, связанный с сериализованным объектом, будет отличаться от serialVersionUID класса, рассчитанного в среде десериализации. В свою очередь десериализация не будет успешной. Поэтому, чтобы избежать таких ситуаций / проблем, программист должен всегда указывать serialVersionUID класса Serializable.

42
ответ дан 15 August 2018 в 16:58
  • 1
    Алгоритм не меняется, но он немного недоопределен. – user207421 21 May 2014 в 02:35
  • 2
    @abbas «Нужно« делать »почему? Пожалуйста, объясните, какая разница. – user207421 25 November 2017 в 12:58
  • 3
    Как сказано в названии, оно представляет собой версию класса, которая использовалась для сериализации объекта. Если вы каждый раз назначаете ему одинаковое число, вы не сможете найти нужный класс для де-сериализации. Поэтому всякий раз, когда вы делаете изменения в классе, лучше также изменить версию. – abbas 27 November 2017 в 04:39
  • 4
    @BillK, я думал, что проверка сериализации связана с парой classname и serialVersionUID. Поэтому разные схемы нумерации разных классов и библиотек никак не могут помешать. Или вы подразумевали библиотеки, генерирующие код? – Vadzim 26 January 2018 в 14:26

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

Похожие вопросы: