Что такое serialVersionUID и почему я должен его использовать?

avatar
ashokgelal
12 ноября 2008 в 23:24
1000236
26
3190

Eclipse выдает предупреждения, когда отсутствует serialVersionUID.

Сериализуемый класс Foo не объявляет статический финал Поле serialVersionUID типа long

Что такое serialVersionUID и почему это важно? Покажите пример, в котором отсутствие serialVersionUID вызовет проблему.

Источник
ceyun
4 ноября 2019 в 11:28
4

Найдите полезный опыт использования serialversionUID; dzone.com/articles/what-is-serialversionuid

Ответы (26)

avatar
Jon Skeet
12 ноября 2008 в 23:30
2434

Документы для java.io.Serializable, вероятно, столь же хорошее объяснение, как и вы:

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

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

Если сериализуемый класс не объявляет явно serialVersionUID, то среда выполнения сериализации вычислит значение по умолчанию serialVersionUID для этого класса на основе различных аспектов класса, как описано в Спецификации сериализации объектов Java (TM). . Однако настоятельно рекомендуется , чтобы все сериализуемые классы явно объявляли значения serialVersionUID, поскольку вычисление serialVersionUID по умолчанию очень чувствительно к деталям класса, которые могут различаться в зависимости от реализаций компилятора и, таким образом, могут привести к неожиданным результатам. InvalidClassExceptions во время десериализации. Следовательно, чтобы гарантировать согласованное значение serialVersionUID в разных реализациях компилятора Java, сериализуемый класс должен объявить явное значение serialVersionUID. Также настоятельно рекомендуется, чтобы явные объявления serialVersionUID использовали модификатор private, где это возможно, поскольку такие объявления применяются только к немедленно объявляющемуся классу - поля serialVersionUID не используются в качестве унаследованных членов.

Ziggy
1 января 2009 в 07:27
353

Итак, по сути, вы говорите, что, если пользователь не понимает всего вышеупомянутого материала, он может не беспокоиться о сериализации? Я полагаю, вы ответили на вопрос "как?" вместо того, чтобы объяснять «почему?». Я, например, не понимаю, почему я вообще беспокоюсь о SerializableVersionUID.

Jon Skeet
1 января 2009 в 20:26
387

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

JohnMerlino
15 июня 2014 в 17:12
19

И почему Eclipse говорит, что мне нужен "private static final long serialVersionUID = 1L;" когда я расширяю класс Exception?

Jon Skeet
15 июня 2014 в 18:43
23

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

zpon
8 октября 2014 в 11:48
17

@JohnMerlino, чтобы ответить на ваш вопрос, почему: Exception реализует Serializable, а eclipse предупреждает, что вы не установили serialVersionUID, что было бы хорошей идеей (если вы не хотите сериализовать класс) для Избегайте проблем, о которых говорится в сообщении JonSkeet.

smwikipedia
22 декабря 2014 в 12:55
1

@JonSkeet Значит ли это, что помимо идентичного определения класса я должен использовать точно такой же номер версии? Как я мог это узнать, если у меня нет возможности взглянуть на исходный код сериализованного класса?

Jon Skeet
22 декабря 2014 в 12:56
7

@smwikipedia: Для десериализации данных? да. Однако было бы странно десериализовать данные для класса, для которого у вас не было источника. Двоичная сериализация не должна (IMO) использоваться в качестве общедоступного протокола общего назначения.

amertkara
10 июля 2015 в 16:17
2

@Ziggy If ".. поскольку вычисление serialVersionUID по умолчанию очень чувствительно к деталям класса, которые могут различаться в зависимости от реализаций компилятора и, таким образом, могут привести к неожиданным InvalidClassExceptions во время десериализации." не отвечает Почему тогда я боюсь, придется попросить вас определить почему: D

Gaurav Jeswani
4 декабря 2015 в 09:03
1

@JonSkeet В своем ответе вы упомянули, что «поскольку такие объявления применяются только к немедленно объявленному классу - поля serialVersionUID не используются в качестве унаследованных членов». не могли бы вы объяснить это? Поскольку, насколько я знаю, если родительский класс сериализуется, дочерний класс также сериализуется по умолчанию, поэтому нам нужно также объявить SerialVersionUID для дочернего элемента?

Jon Skeet
4 декабря 2015 в 09:04
2

@proudandhonour: Да, вы должны это сделать.

Gaurav Jeswani
4 декабря 2015 в 09:06
0

@JonSkeet Если я сделаю его защищенным, то что? Не будет ли это унаследовано в дочернем классе?

Jon Skeet
4 декабря 2015 в 09:12
1

@proudandhonour: Я точно не знаю, что происходит в этих случаях, но почему бы просто не объявить это отдельно в каждом классе, как следует из документации?

JimLohse
20 декабря 2015 в 17:17
2

Всего два цента, это проблема Spark и других API-интерфейсов распараллеливания, которые зависят от сериализации классов Java в кластере.

Asif Mushtaq
28 июня 2016 в 19:29
1

@JonSkeet, кто генерирует UID по умолчанию? JVM или компилятор / JDK?

Jon Skeet
28 июня 2016 в 19:37
1

@UnKnown: среда выполнения сериализации - это время выполнения.

user1050755
11 июня 2017 в 19:36
1

Итак, если я правильно понимаю, указывать uid вручную небезопасно, чем позволять среде выполнения генерировать его. Потому что рано или поздно кто-то его забудет обновить ....

Jon Skeet
11 июня 2017 в 21:29
4

@ user1050755: В принципе, у каждого есть свои плюсы и минусы.

user1050755
12 июня 2017 в 01:45
1

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

Jon Skeet
12 июня 2017 в 05:47
5

@ user1050755: Итак, вы счастливы, что изменение вашего компилятора, даже если оно не изменит никаких деталей самих полей, может сделать любые сохраненные данные нечитаемыми? Или добавление общедоступного статического метода, который действительно не должен изменять детали сериализации? Раньше я был укушен подобными вещами, поэтому это явный "недостаток". Теперь могло случиться так, что если бы алгоритм был разработан лучше, все было бы хорошо, но с учетом того, как он разработан , это плохие новости.

android developer
4 июня 2018 в 08:33
2

Совет: если вы забыли добавить serialVersionUIDfield и хотите изменить класс, не затрагивая его, вы можете проверить его значение на немодифицированном и установить его для этого класса после того, как вы его изменили, используя это Звоните (можно найти с: coderhelper.com/a/26822688/878126): long serialVersionUID = ObjectStreamClass.lookup(YourClass.class).getSerialVersionUID();

Darrell Teague
9 июля 2018 в 17:44
1

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

bpoiss
19 августа 2019 в 12:33
2

Итак, что произойдет, если я обновлю свой класс, но не обновлю serialVersionUIDfield?

Jon Skeet
19 августа 2019 в 12:37
5

@bpoiss: Затем он попытается десериализовать старые данные с помощью нового класса и либо вызовет ошибки, либо фактически повредит данные, в зависимости от точного изменения.

avatar
Hari Krishna
20 января 2020 в 15:14
3

'serialVersionUID' - это 64-битное число, используемое для уникальной идентификации класса в процессе десериализации. Когда вы сериализуете объект, serialVersionUID класса также записывается в файл. Всякий раз, когда вы десериализуете этот объект, среда выполнения java извлекает это значение serialVersionUID из сериализованных данных и сравнивает то же значение, связанное с классом. Если оба не совпадают, будет сгенерировано исключение java.io.InvalidClassException.

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

avatar
forkdbloke
15 ноября 2019 в 16:06
0

Что такое SerialVersionUID? Ответ: - Допустим, есть два человека, один из штаб-квартиры, а другой из ODC, оба будут выполнять сериализацию и десериализацию соответственно. В этом случае для подтверждения того, что получатель, находящийся в ODC, является аутентифицированным лицом, JVM создает уникальный идентификатор, который известен как SerialVersionUID.

Вот хорошее объяснение, основанное на сценарии,

Почему SerialVersionUID?

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

Десериализация : во время десериализации JVM на стороне получателя будет сравнивать уникальный идентификатор, связанный с объектом, с уникальным идентификатором локального класса, т.е. JVM также создаст уникальный идентификатор на основе соответствующего файла .class, который присутствует в системе приемника. Если оба уникальных идентификатора совпадают, будет выполнена только десериализация. В противном случае мы получим исключение времени выполнения с сообщением InvalidClassException. Этот уникальный идентификатор - не что иное, как SerialVersionUID

avatar
Shanks D Shiva
29 апреля 2019 в 05:06
1

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

Сериализация: Мы часто работаем с важными объектами, состояние которых (данные в переменных объекта) настолько важно, что мы не можем рисковать потерять его из-за сбоев питания / системы (или) сетевых сбоев в случае отправки состояния объекта на другую машину. Решение этой проблемы называется «Постоянство», что просто означает сохранение (удержание / сохранение) данных. Сериализация - это один из многих других способов достижения постоянства (путем сохранения данных на диск / в память). При сохранении состояния объекта важно создать идентификатор для объекта, чтобы иметь возможность правильно прочитать его обратно (десериализация). Этот уникальный идентификатор - это идентификатор SerialVersionUID.

avatar
Stanislav Orlov
15 апреля 2019 в 16:55
1

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

  • у вас есть много разных копий вашей программы в разных местах (например, 1 сервер и 100 клиентов). Если вы измените свой объект, измените номер версии и забудете обновить одного из этих клиентов, он будет знать, что он не может десериализоваться

  • вы сохранили свои данные в каком-то файле, а позже вы пытаетесь открыть его с помощью обновленной версии вашей программы с измененным объектом - вы узнаете, что этот файл несовместим, если сохраните свою версию правильно

Когда это важно?

Наиболее очевидно - если вы добавите несколько полей в свой объект, более старые версии не смогут их использовать, потому что у них нет этих полей в своей структуре объекта.

Менее очевидно - когда вы десериализуете объект, поля, которых нет в строке, будут сохранены как NULL. Если вы удалили поле из своего объекта, более старые версии сохранят это поле как всегда-NULL, что может привести к неправильному поведению, если более старые версии полагаются на данные в этом поле (в любом случае вы создали его для чего-то, а не только для развлечения :-))

Наименее очевидный - Иногда вы меняете идею, которую вкладываете в значение некоторого поля. Например, когда вам 12 лет, вы подразумеваете «велосипед» под «байком», но когда вам 18, вы имеете в виду «мотоцикл» - если ваши друзья пригласят вас «прокатиться на велосипеде по городу», и вы будете единственным, кто приехал на велосипеде, вы поймете, насколько важно сохранять одинаковый смысл в полях :-)

avatar
gagarwa
16 января 2019 в 23:29
3

Простое объяснение:

  1. Вы сериализуете данные?

    Сериализация - это в основном запись данных класса в файл / поток / и т. Д. Десериализация - это чтение этих данных обратно в класс.

  2. Собираетесь ли вы начать производство?

    Если вы просто тестируете что-то с несущественными / поддельными данными, не беспокойтесь об этом (если вы не тестируете сериализацию напрямую).

  3. Это первая версия?

    Если да, установите serialVersionUID=1L.

  4. Это вторая, третья и т. Д. Версия продукта?

    Теперь вам нужно побеспокоиться о serialVersionUID и изучить его более подробно.

Обычно, если вы неправильно обновляете версию при обновлении класса, который нужно писать / читать, вы получите сообщение об ошибке при попытке прочитать старые данные.

avatar
JegsVala
22 января 2018 в 04:27
51

Сначала мне нужно объяснить, что такое сериализация.

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

Существуют некоторые правила сериализации .

  • Объект сериализуем, только если его класс или его суперкласс реализует интерфейс Serializable

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

  • Все примитивные типы сериализуемы.

  • Поля переходного процесса (с модификатором переходного процесса) НЕ сериализуются (т. Е. Не сохраняются и не восстанавливаются). Класс, реализующий Serializable, должен отмечать переходные поля классов, которые не поддерживают сериализацию (например, файловый поток).

  • Статические поля (со статическим модификатором) не сериализуются.

Когда Object сериализуется, среда выполнения Java связывает серийный номер версии, также известный как serialVersionID.

Где нам нужен serialVersionID:

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

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

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() {
        return getEmpName() + " is " + getEmpAge() + "years old";
    }
}

Создать объект сериализации

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");
    }
}

Десериализовать объект

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)
Victor
3 июня 2020 в 13:03
0

Поправьте меня, если я ошибаюсь - локальный класс - это тот, который вы в настоящее время используете / используете в пути к классам, а поток - это тот, который используется другой стороной (например, сервер, который возвращает вам ответ и сериализует отклик). Вы можете столкнуться с этой ситуацией, когда общаетесь с сервером, который обновил свои сторонние библиотеки, но вы (клиент) этого не сделали.

avatar
roottraveller
7 марта 2017 в 05:48
11

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

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

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

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

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

avatar
Naved Ali
17 апреля 2016 в 19:42
6

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

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

user207421
25 ноября 2017 в 09:00
1

Каждый раз, когда класс объекта сериализуется, передается serialVersionUID. Он отправляется не со всеми объектами.

avatar
Geek
3 августа 2015 в 19:41
6

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

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

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

avatar
schnell18
27 июня 2015 в 12:36
8

Если вы хотите изменить огромное количество классов, для которых в первую очередь не было задано 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 находится в ПУТИ.

Ignazio
17 марта 2016 в 18:05
2

Это дает мне идею: всегда регенерируйте uid серийной версии с помощью такого инструмента, а не вручную, перед выпуском - таким образом вы не забудете внести изменения в класс, чей uid серийной версии должен был измениться из-за фактического несовместимое изменение. Отследить это вручную очень сложно.

avatar
Coder123
25 марта 2015 в 21:08
12

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

Подробнее: http://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html#ixzz3VQxnpOPZ

avatar
Archimedes Trajano
4 марта 2014 в 16:17
16

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

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

Во всех остальных случаях я использую

@SuppressWarnings("serial")

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

user207421
20 мая 2014 в 21:36
0

Он не включает HttpServlet в контейнеры, где они могут быть заменены, или Exception в RMI, например.

avatar
Thalaivar
17 октября 2013 в 04:28
76

Что такое serialVersionUID и почему я должен его использовать?

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

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

javadocs для Serializable, например, :

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

Следовательно, вы должны объявить serialVersionUID, потому что это дает нам больше контроля .

В этой статье есть несколько хороших моментов по этой теме.

Kranthi Sama
16 июня 2014 в 11:06
3

@Vinothbabu, но serialVersionUID является статическим, поэтому статические переменные не могут быть сериализованы. тогда как получилось, что jvm проверит версию, не зная, какая версия десериализуемого объекта

Kirby
17 июня 2014 в 16:30
3

Единственное, о чем не упоминается в этом ответе, - это то, что вы можете вызвать непредвиденные последствия, слепо включив serialVersionUID, не зная почему. Комментарий Тома Андерсона к ответу MetroidFan2002 касается этого: «Я бы сказал, что если вы не используете сериализацию для постоянного хранения, вам следует использовать @SuppressWarnings, а не добавлять значение. Это меньше загромождает класс и сохраняет способность Механизм serialVersionUID для защиты от несовместимых изменений. "

user207421
9 июня 2015 в 04:17
8

serialVersionUID - это , а не «уникальный идентификатор для каждого класса». Это полное имя класса. Это индикатор версии .

avatar
Nitesh Soni
2 июня 2013 в 06:20
22

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

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

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

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

user207421
20 мая 2014 в 21:35
2

Алгоритм не меняется, но немного занижен.

AnthonyJClink
30 августа 2019 в 01:01
0

... алгоритм не меняется, но он немного недооценен ... это означает, что любой jvm может отличаться ..... @ user207421

avatar
Henrique Ordine
20 мая 2013 в 19:32
20

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

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

Этот класс POJO's был упакован внутри jar-файла EJB и внутри собственного jar-файла в 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
avatar
Rupesh
7 апреля 2013 в 10:43
61

В исходном вопросе был задан вопрос «почему это важно» и «пример», где этот Serial Version ID был бы полезен. Что ж, я нашел одну.

Допустим, вы создали класс Car, создали его экземпляр и записали в поток объектов. Сплющенный объект автомобиля некоторое время находится в файловой системе. Между тем, если класс Car изменен путем добавления нового поля. Позже, когда вы попытаетесь прочитать (т.е. десериализовать) сплющенный объект Car, вы получите java.io.InvalidClassException - потому что всем сериализуемым классам автоматически присваивается уникальный идентификатор. Это исключение возникает, когда идентификатор класса не равен идентификатору сглаженного объекта. Если вы действительно думаете об этом, исключение выдается из-за добавления нового поля. Вы можете избежать возникновения этого исключения, контролируя управление версиями самостоятельно, объявив явный serialVersionUID. Также есть небольшое преимущество в производительности при явном объявлении вашего serialVersionUID (поскольку его не нужно вычислять). Итак, лучше всего добавить свой собственный serialVersionUID в классы Serializable сразу после их создания, как показано ниже:

public class Car {
    static final long serialVersionUID = 1L; //assign a long value
}
abbas
27 октября 2017 в 01:34
0

И каждому UID следует присвоить случайное длинное число, а не 1L.

user207421
25 ноября 2017 в 08:58
5

@abbas 'Надо' так почему? Пожалуйста, объясните, в чем разница.

abbas
27 ноября 2017 в 00:39
0

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

Vadzim
14 декабря 2017 в 18:21
3

@abbas, это намерение не противоречит использованию возрастающих натуральных чисел от 1 и так далее.

Vadzim
26 января 2018 в 10:26
3

@BillK, я думал, что проверка сериализации привязана к паре classname и serialVersionUID. Так что разные схемы нумерации разных классов и библиотек никак не могут мешать. Или вы имели в виду библиотеки для генерации кода?

user207421
22 марта 2018 в 10:28
1

@abbas serialVersionUID не имеет ничего общего с «поиском правильной версии класса».

Volksman
2 мая 2020 в 10:35
1

То, что я всегда находил безумным, заключалось в том, что алгоритм получения serialVersionUID, когда ни один явно не объявлен, основан на пакете, имени, атрибутах, но ТАКЖЕ методы ... методы не сериализуются, а добавление / удаление методов не влияет на сериализованную форму объект, так зачем создавать другой serialVersionUID при добавлении / удалении / изменении метода »?

avatar
Mukti
13 марта 2013 в 14:26
14

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

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

@SuppressWarnings("serial")
avatar
Alexander Torstling
3 октября 2012 в 06:05
118

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

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

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

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

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

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

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

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

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

user207421
7 февраля 2014 в 01:05
4

Добавление или удаление непереходных полей не делает класс несовместимым с сериализацией. Следовательно, нет никаких оснований «навязывать» такие изменения.

Alexander Torstling
7 февраля 2014 в 19:12
4

@EJP: А? Добавление данных определенно меняет данные сериализации в моем мире.

user207421
20 мая 2014 в 21:27
3

@AlexanderTorstling Прочтите, что я написал. Я не сказал, что это не «меняет данные сериализации». Я сказал, что это «не делает сериализацию классов несовместимой». Это не одно и то же. Вам необходимо прочитать главу «Управление версиями» Спецификации сериализации объектов.

Alexander Torstling
21 мая 2014 в 06:42
3

@EJP: Я понимаю, что добавление непереходного поля не обязательно означает, что вы делаете класс несовместимым с сериализацией, но это структурное изменение, которое изменяет сериализованные данные, и вы обычно хотите поднять версию при этом, если вы не обрабатывать обратную совместимость, что я также объяснил позже в этом посте. Что именно вы хотите сказать?

user207421
4 мая 2015 в 11:16
4

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

avatar
grand johnson
29 апреля 2012 в 15:59
17

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

user207421
22 марта 2018 в 10:30
4

Мусор. Достаточно в том случае, если класс не изменился. У вас нет никаких доказательств, подтверждающих «99,9999%».

Dorian Gray
3 ноября 2020 в 15:44
1

Проблема не в том, что он «плохой», но нет гарантии, что он будет соответствовать разным версиям.

The incredible Jan
9 апреля 2021 в 12:32
0

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

avatar
Paŭlo Ebermann
3 февраля 2011 в 00:32
34

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

Итак, вместо

public class MyExample extends ArrayList<String> {

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

делать

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. Я думаю, что в этом случае не должно быть предупреждения (поскольку обычно вы не можете надежно сериализовать и десериализовать такие анонимные классы в любом случае в разных версиях вашего класса), но я не уверен, как компилятор мог это распознать.

piepera
7 декабря 2011 в 15:20
4

Думаю, вы правы в том, что композиция важнее инертности, особенно когда вы обсуждаете такие классы, как ArrayList. Однако многие фреймворки требуют, чтобы люди расширялись от абстрактных суперклассов, которые можно сериализовать (например, класс ActionForm Struts 1.2 или Saxon ExtensionFunctionDefinition), и в этом случае это решение невозможно. Я думаю, что вы правы, было бы неплохо, если бы предупреждение игнорировалось в определенных случаях (например, если бы вы расширялись из абстрактного сериализуемого класса)

M_M
19 августа 2012 в 22:15
2

Конечно, если вы добавляете класс в качестве члена, а не наследуете от него, вам придется написать метод-оболочку для КАЖДОГО метода класса-члена, который вы хотите использовать, что сделает его невозможным в большом количестве ситуаций. ... если в java нет функции, аналогичной perl __AUTOLOAD, о которой я не знаю.

Paŭlo Ebermann
20 августа 2012 в 08:09
4

@M_M: Когда вы делегируете множество методов своему обернутому объекту, конечно, было бы нецелесообразно использовать делегирование. Но я полагаю, что этот случай является признаком ошибки дизайна - пользователям вашего класса (например, «MainGui») не нужно вызывать множество методов обернутого объекта (например, JFrame).

WVrock
29 ноября 2014 в 07:14
1

Что мне не нравится в делегировании, так это необходимость содержать ссылку на делегата. И каждая ссылка означает больше памяти. Поправьте меня если я ошибаюсь. Если мне нужен CustomizdeArrayList из 100 объектов, это не имеет большого значения, но если мне нужны сотни CustomizdeArrayList из нескольких объектов, использование памяти значительно возрастет.

Phil
13 апреля 2017 в 02:59
2

Throwable является сериализуемым, и только Throwable может быть выброшен, поэтому невозможно определить исключение, которое не сериализуемо. Делегирование невозможно.

Paŭlo Ebermann
18 апреля 2017 в 07:38
0

@Phil Я думаю, что это сделано намеренно - даже если вы не хотите сериализовать свой класс исключения, кто-то другой может захотеть сериализовать созданное вами исключение. (Конечно, можно утверждать, что большинство классов исключений должно работать с автоматически сгенерированным serialVersionUID и не нуждаться в фиксированном.)

Rogue
13 июня 2017 в 13:42
0

@WVrock Что ж, ничего бы не изменилось, если бы у вас было много экземпляров ArrayList. Экземпляр вашего класса-оболочки имеет размер порядка байтов + размер arrayylist, тогда как через наследование вы инициализируете такое же количество, но в соответствии с определением 1 класса. Ссылки легкие, лежащие в основе объекты тяжелые.

avatar
David Wright
3 декабря 2008 в 14:44
11

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

Paŭlo Ebermann
20 февраля 2011 в 02:04
8

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

Andrew
9 августа 2011 в 08:29
4

Причина в том, что разные компиляторы дают одно и то же значение для одного и того же класса. Как объясняется в документации javadocs (на которую также дан ответ выше), сгенерированная версия является хрупкой и может изменяться, даже если класс десериализуем должным образом. Пока вы запускаете этот тест каждый раз на одном и том же компиляторе, он должен быть безопасным. Бог поможет вам, если вы обновите jdk и появится новое правило, даже если ваш код не изменился.

user207421
7 февраля 2014 в 01:10
2

Не обязательно совпадать с тем, что произведет serialver. -1

Bill K
25 января 2018 в 21:06
0

В общем, это совсем не обязательно. В случае @ AndrewBacker потребуется два разных компилятора для одного и того же файла .java с обеими версиями файлов .class, взаимодействующими друг с другом - в большинстве случаев вы просто создаете класс и распространяете его. Если это так, то подойдет и отсутствие SUID.

john16384
10 февраля 2018 в 11:11
2

Люди, которые действительно используют сериализацию для хранения / извлечения, обычно устанавливают serialVersionUID на 1. Если более новая версия класса несовместима, но по-прежнему требует возможности обработки старых данных, вы увеличиваете номер версии и добавляете специальный код для работы со старыми форматами. Я плачу каждый раз, когда вижу число serialVersionUID, превышающее 1 цифру, либо потому, что это было случайное число (бесполезно), либо потому, что классу явно нужно иметь дело с более чем 10 различными версиями.

avatar
MetroidFan2002
13 ноября 2008 в 04:24
493

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

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

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

Tom Anderson
24 апреля 2011 в 10:43
82

Я бы сказал, что если вы не используете сериализацию для постоянного хранения, вам следует использовать @SuppressWarnings, а не добавлять значение. Он меньше загромождает класс и сохраняет способность механизма serialVersionUID защищать вас от несовместимых изменений.

MetroidFan2002
25 апреля 2011 в 17:09
26

Я не вижу, как добавление одной строки (аннотация @SuppressWarnings) в противоположность другой строке (сериализуемый идентификатор) «меньше загромождает класс». И если вы не используете сериализацию для постоянного хранения, почему бы вам просто не использовать «1»? В любом случае вам не будет важен автоматически сгенерированный идентификатор.

AbdullahC
30 декабря 2011 в 14:32
72

@ MetroidFan2002: Я думаю, что точка зрения @ TomAnderson serialVersionUID, защищающая вас от несовместимых изменений, верна. Использование @SuppressWarnings лучше документирует намерение, если вы не хотите использовать класс для постоянного хранения.

user207421
12 декабря 2012 в 00:59
11

«Вы должны увеличить его, если текущая версия вашего класса не имеет обратной совместимости с предыдущей версией:» Сначала вы должны изучить обширную поддержку управления версиями объектов в сериализации, (а) чтобы убедиться, что класс действительно теперь несовместим с сериализацией, чего по спецификации достичь довольно сложно; (б) попробовать такую ​​схему, как пользовательские методы чтения / записиObject (), методы readResolve / writeReplace (), объявления serializableFields и т. д., чтобы убедиться, что поток остается совместимым. Изменение действительного serialVersionUID - последнее средство, совет отчаяния.

overexchange
24 декабря 2014 в 15:39
4

@EJP приращение serialVersionUID появляется, когда первоначальный автор класса явно представил его. Я бы сказал, что сгенерированный jvm серийный идентификатор должен быть в порядке. это лучший ответ, который я видел по сериализации.

user207421
4 мая 2015 в 11:17
0

@overexchange Что означает "явно введено"?

overexchange
4 мая 2015 в 11:27
0

Я имею в виду явно заявлено

user207421
25 ноября 2017 в 09:11
0

@overexchange Вы имеете в виду «объявлено» , что «явно»?

overexchange
25 ноября 2017 в 09:13
0

@EJP Явно объявлен serialVersionUID.

john16384
10 февраля 2018 в 11:06
0

Если вы не используете сериализацию (примерно в 99,9999% случаев), просто отключите это глупое предупреждение по умолчанию. Никаких бессмысленных бессмысленных случайных чисел в вашем коде и никаких ненужных предупреждений SuppressWarning. Боже, каждый раз, когда я вижу базы кода, которые «обходят» это предупреждение, я действительно удивляюсь, почему они просто не отключают это предупреждение (и, возможно, активируют несколько более полезных), вместо этого зомби-менталитета, чтобы просто «исправить» предупреждение.

Alex78191
8 июня 2018 в 00:53
0

@TomAnderson По умолчанию в IDEA предупреждения не отображаются.

user207421
26 июля 2019 в 11:04
0

@overexchange Я полностью согласен с ответом @JBNizet, но там ничего не говорится об увеличении serialVersionUID. Вы должны либо оставить его в покое, либо изменить его на новое вычисленное значение, как сообщает инструмент serialver, предварительно тщательно изучив альтернативы, о которых я упоминал, и даже до этого определенно определив, что это действительно нужно изменить, что обычно нет. Намеренно вводить несовместимые средства, особенно если они бесплатны, не дает никаких результатов.

avatar
matt b
13 ноября 2008 в 01:17
140

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

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

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

  • Возможные проблемы программирования: возможное случайное логическое присвоение
  • Возможные проблемы программирования: доступ к нулевому указателю
  • Ненужный код: локальная переменная никогда не читается
  • Ненужный код: избыточная нулевая проверка
  • Ненужный код: ненужное приведение или instanceof

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

John Gardner
13 ноября 2008 в 01:28
23

проголосовать за, но только потому, что исходный постер, похоже, ничего не сериализирует. Если бы на плакате было написано «Я сериализую эту штуку и ...», то вместо этого вы получите голос «против»: P

matt b
13 ноября 2008 в 02:52
4

Верно - я предполагал, что спрашивающий просто не хотел, чтобы его предупреждали

Ziggy
1 января 2009 в 07:29
15

@Gardner -> согласен! Но спрашивающий также хочет знать, почему он может не хотеть, чтобы его предупреждали.

cinqS
18 апреля 2017 в 03:31
9

Спрашивающего явно волнует, почему должен быть UID. Поэтому простое указание ему игнорировать предупреждение должно быть отвергнуто.

avatar
Scott Bale
12 ноября 2008 в 23:37
324

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

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

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

Ziggy
1 января 2009 в 07:28
38

Итак, можно было бы побеспокоиться о SerializableVersionUID, если бы вы беспокоились о совместимости со старыми версиями класса?

Chander Shivdasani
13 января 2012 в 19:49
12

Да, в случае, если более новая версия изменит какой-либо публичный член на защищенный, SerializableVersionUID по умолчанию будет другим и вызовет InvalidClassExceptions.

Achow
1 марта 2013 в 04:38
3

Имя класса, реализованные интерфейсы, все общедоступные и защищенные методы, ВСЕ переменные экземпляра.

Ashutosh Jindal
8 июля 2014 в 13:25
34

Стоит отметить, что Джошуа Блох советует для каждого сериализуемого класса указывать uid последовательной версии. Цитата из главы 11: Независимо от того, какую сериализованную форму вы выберете, объявляйте явный UID последовательной версии в каждом сериализуемом классе, который вы пишете. Это исключает UID серийной версии как потенциальный источник несовместимости (элемент 74). Также есть небольшой выигрыш в производительности. Если не указан UID серийной версии, для его генерации во время выполнения требуются дорогостоящие вычисления.

Ben
20 декабря 2020 в 08:29
1

Кажется актуальным. Ссылка на пару подходов для создания UID последовательной версии с использованием IDE: mkyong.com/java/how-to-generate-serialversionuid

avatar
eishay
12 ноября 2008 в 23:30
39

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

erickson
13 ноября 2008 в 05:34
11

Если вы не собираетесь сериализовать объекты, почему они сериализуемы?

MetroidFan2002
30 марта 2009 в 14:12
7

@erickson - родительский класс может быть сериализуемым, например, ArrayList, но вы хотите, чтобы ваш собственный объект (скажем, модифицированный список массивов) использовал его в качестве основы, но вы никогда не собираетесь сериализовать созданную вами коллекцию.

user207421
7 февраля 2014 в 01:10
5

Это нигде не упоминается в Спецификации языка Java. Это упоминается в Спецификации управления версиями объектов.

Basil Bourque
3 ноября 2014 в 04:12
4

Вот ссылка на спецификацию управления версиями объектов Java 8 .