etc./StackOverFlow

serialVersionUID란 무엇이며 왜 사용해야 합니까?

청렴결백한 만능 재주꾼 2021. 11. 5. 23:09
반응형

질문자 :ashokgelal


serialVersionUID 가 누락된 경우 경고를 발행합니다.

직렬화 가능한 클래스 Foo는 long 유형의 정적 최종 serialVersionUID 필드를 선언하지 않습니다.

serialVersionUID 란 무엇이며 왜 중요한가요? serialVersionUID 로 인해 문제가 발생하는 예를 보여주세요.



java.io.Serializable 에 대한 문서는 아마도 다음과 같은 좋은 설명을 얻을 수 있을 것입니다.

직렬화 런타임은 직렬화 가능한 각 클래스에 serialVersionUID 라고 하는 버전 번호를 연결하여 직렬화와 관련하여 호환되는 해당 개체의 로드된 클래스를 직렬화된 개체의 보낸 사람과 수신기에 로드했는지 확인하기 위해 역직렬화 중에 사용됩니다. 수신자가 해당 발신자의 클래스 serialVersionUID 가 다른 객체에 대한 클래스를 로드한 경우 InvalidClassException 이 발생합니다. 직렬화 가능한 클래스는 static, final 및 long serialVersionUID 라는 필드를 선언하여 명시적으로 serialVersionUID 선언할 수 있습니다.

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

serialVersionUID 명시적으로 선언하지 않으면 직렬화 런타임은 Java(TM) 개체 직렬화 사양에 설명된 대로 클래스의 다양한 측면을 기반으로 해당 클래스에 대한 serialVersionUID 그러나 serialVersionUID 계산은 컴파일러 구현에 따라 다를 수 있는 클래스 세부 정보에 매우 민감하므로 직렬화 해제 중에 InvalidClassExceptions 이 발생할 수 있으므로 모든 직렬화 가능 클래스가 serialVersionUID 값을 명시적으로 선언하는 것이 좋습니다. serialVersionUID 값을 보장하려면 직렬화 가능 클래스가 명시적 serialVersionUID 값을 선언해야 합니다. 또한 명시적 serialVersionUID 선언은 가능한 경우 private 한정자를 사용하는 것이 좋습니다. 이러한 선언은 즉시 선언하는 클래스에만 적용되기 때문입니다. serialVersionUID 필드는 상속된 멤버로 유용하지 않습니다.


Jon Skeet

구현을 위해 직렬화해야 하기 때문에 직렬화하는 경우( HTTPSession 직렬화 여부에 상관없이 ... 저장 여부에 관계없이 양식 개체의 de-serializing 대해서는 신경 쓰지 않을 것입니다) , 당신은 이것을 무시할 수 있습니다.

실제로 직렬화를 사용하는 경우 직렬화를 직접 사용하여 객체를 저장하고 검색하려는 경우에만 중요합니다. serialVersionUID 는 클래스 버전을 나타내며 현재 클래스 버전이 이전 버전과 역호환되지 않는 경우 이를 증가시켜야 합니다.

대부분의 경우 직렬화를 직접 사용하지 않을 것입니다. 이 경우 빠른 수정 옵션을 클릭하여 SerialVersionUID


MetroidFan2002

Josh Bloch의 책 Effective Java (2nd Edition)를 연결할 수 있는 이 기회를 놓칠 수 없습니다. 10장은 Java 직렬화에 대한 필수 리소스입니다.

Josh에 따라 자동으로 생성된 UID는 클래스 이름, 구현된 인터페이스, 모든 공개 및 보호 멤버를 기반으로 생성됩니다. 어떤 식으로든 이들 중 하나를 변경하면 serialVersionUID 가 변경됩니다. 따라서 하나 이상의 클래스 버전이 직렬화되지 않을 것이라고 확신하는 경우(프로세스 전반에 걸쳐 또는 나중에 저장소에서 검색됨)에만 그것들을 엉망으로 만들 필요가 없습니다.

지금은 무시하고 나중에 어떤 방식으로든 클래스를 변경해야 하지만 클래스의 이전 버전과의 호환성을 유지해야 한다는 것을 알게 되면 JDK 도구 serialver 를 사용하여 이전 serialVersionUID 를 생성하고 명시적으로 설정할 수 있습니다. 새 수업에서 말이다. writeObjectreadObject 메소드를 추가하여 사용자 정의 직렬화를 구현해야 할 수도 있습니다. Serializable javadoc 또는 앞서 언급한 10장을 참조하십시오.)


Scott Bale

다음 serialVersionUID 경고를 무시하도록 Eclipse에 지시할 수 있습니다.

창 > 환경 설정 > Java > 컴파일러 > 오류/경고 > 잠재적인 프로그래밍 문제

모르는 경우를 대비하여 이 섹션에서 활성화할 수 있는 다른 많은 경고가 있으며(또는 일부는 오류로 보고된 경우도 있음) 많은 경고가 매우 유용합니다.

  • 잠재적인 프로그래밍 문제: 우연한 부울 할당 가능성
  • 잠재적인 프로그래밍 문제: 널 포인터 액세스
  • 불필요한 코드: 지역 변수를 절대 읽지 않습니다.
  • 불필요한 코드: 중복 null 검사
  • 불필요한 코드: 불필요한 캐스트 또는 'instanceof'

그리고 더 많은.


matt b

serialVersionUID 는 직렬화된 데이터의 버전 관리를 용이하게 합니다. 그 값은 직렬화할 때 데이터와 함께 저장됩니다. 역직렬화할 때 직렬화된 데이터가 현재 코드와 어떻게 일치하는지 확인하기 위해 동일한 버전이 확인됩니다.

데이터 버전을 지정하려면 일반적으로 serialVersionUID 0으로 시작하고 직렬화된 데이터를 변경하는 클래스의 모든 구조적 변경(비일시적 필드 추가 또는 제거)과 함께 충돌합니다.

기본 제공 역직렬화 메커니즘( in.defaultReadObject() )은 데이터의 이전 버전에서 역직렬화를 거부합니다. 그러나 원하는 경우 이전 데이터를 다시 읽을 수 있는 자체 readObject() 함수를 정의할 수 있습니다. 그런 다음 이 사용자 정의 코드는 데이터가 어떤 버전인지 확인하고 직렬화 해제 방법을 결정하기 위해 serialVersionUID 이 버전 관리 기술은 코드의 여러 버전에서 살아남는 직렬화된 데이터를 저장하는 경우에 유용합니다.

그러나 이렇게 오랜 기간 동안 직렬화된 데이터를 저장하는 것은 그리 일반적이지 않습니다. 직렬화 메커니즘을 사용하여 데이터를 임시로 캐시에 쓰거나 네트워크를 통해 코드베이스의 관련 부분과 동일한 버전을 가진 다른 프로그램으로 보내는 것이 훨씬 더 일반적입니다.

이 경우 이전 버전과의 호환성을 유지하는 데 관심이 없습니다. 통신하는 코드 베이스가 실제로 동일한 버전의 관련 클래스를 갖고 있는지 확인하는 데만 관심이 있습니다. 이러한 확인을 용이하게 하려면 serialVersionUID 를 유지 관리해야 하며 클래스를 변경할 때 업데이트하는 것을 잊지 마십시오.

serialVersionUID 는 같은 클래스의 두 가지 버전으로 끝날 수 있습니다. 이 경우 기본 메커니즘( in.defaultReadObject() )은 차이를 감지하지 않고 호환되지 않는 데이터를 역직렬화하려고 시도합니다. 이제 애매한 런타임 오류 또는 자동 실패(null 필드)로 끝날 수 있습니다. 이러한 유형의 오류는 찾기 어려울 수 있습니다.

따라서 이 사용 사례를 돕기 위해 Java 플랫폼은 serialVersionUID 수동으로 설정하지 않는 선택을 제공합니다. 대신 클래스 구조의 해시가 컴파일 타임에 생성되어 id로 사용됩니다. 이 메커니즘은 동일한 ID를 가진 다른 클래스 구조가 없도록 하므로 위에서 언급한 추적하기 어려운 런타임 직렬화 오류가 발생하지 않습니다.

그러나 자동 생성된 ID 전략에는 뒷면이 있습니다. 즉, 동일한 클래스에 대해 생성된 ID가 컴파일러마다 다를 수 있습니다(위의 Jon Skeet이 언급한 대로). 따라서 다른 컴파일러로 컴파일된 코드 간에 직렬화된 데이터를 통신하는 경우 어쨌든 수동으로 ID를 유지하는 것이 좋습니다.

그리고 언급한 첫 번째 사용 사례와 같이 데이터와 하위 호환이 가능하다면 ID를 직접 유지하고 싶을 수도 있습니다. 이것은 읽을 수 있는 ID를 얻고 변경 시기와 방법을 더 잘 제어하기 위한 것입니다.


Alexander Torstling

serialVersionUID 란 무엇이며 왜 사용해야 합니까?

SerialVersionUID 는 각 클래스에 대한 고유 식별자이며 JVM 은 이를 사용하여 직렬화 중에 사용된 동일한 클래스가 역직렬화 중에 로드되도록 클래스 버전을 비교합니다.

하나를 지정하면 더 많은 제어가 제공되지만 지정하지 않으면 JVM이 하나를 생성합니다. 생성된 값은 컴파일러마다 다를 수 있습니다. 게다가, 때때로 당신은 어떤 이유에서 이전 직렬화된 객체의 역직렬화를 금지하기를 원할 때가 있습니다[ backward incompatibility ]. 이 경우에는 serialVersionUID만 변경하면 됩니다.

Serializable 대한 javadocs는 다음과 같이 말합니다 .

기본 serialVersionUID 계산은 컴파일러 구현에 따라 다를 수 있는 클래스 세부 정보에 매우 민감하므로 역직렬화 중에 InvalidClassException

따라서 serialVersionUID는 더 많은 제어를 제공하므로 선언해야 합니다 .

이 기사 에는 주제에 대한 몇 가지 좋은 점이 있습니다.


Thalaivar

Serial Version ID 가 유용한 '왜 중요한가'와 '예시'에 대해 질문했습니다. 글쎄, 나는 하나를 찾았습니다.

Car 클래스를 만들고 인스턴스화한 다음 개체 스트림에 작성한다고 가정해 보겠습니다. 평평한 자동차 객체는 한동안 파일 시스템에 남아 있습니다. 한편, Car 클래스가 새로운 필드를 추가하여 수정되는 경우. Car 객체를 읽으려고(즉, 역직렬화) 시도 java.io.InvalidClassException 합니다. 직렬화 가능한 모든 클래스에 자동으로 고유 식별자가 부여되기 때문입니다. 이 예외는 클래스의 식별자가 평면화된 개체의 식별자와 같지 않을 때 발생합니다. 곰곰이 생각해보면 새 필드 추가로 인해 예외가 발생합니다. 명시적 serialVersionUID를 선언하여 직접 버전 관리를 제어하여 이 예외가 발생하는 것을 방지할 수 있습니다. serialVersionUID 를 명시적으로 선언하면 약간의 성능 이점이 있습니다(계산할 필요가 없기 때문에). 따라서 아래와 같이 생성하는 즉시 Serializable 클래스에 자신의 serialVersionUID를 추가하는 것이 가장 좋습니다.

 public class Car { static final long serialVersionUID = 1L; //assign a long value }

Rupesh

먼저 직렬화가 무엇인지 설명해야 합니다.

직렬화를 통해 네트워크를 통해 해당 개체를 보내기 위해 개체를 스트림으로 변환하거나 파일에 저장하거나 문자 사용을 위해 DB에 저장할 수 있습니다.

직렬화에는 몇 가지 규칙이 있습니다 .

  • 객체는 해당 클래스 또는 상위 클래스가 직렬화 가능 인터페이스를 구현하는 경우에만 직렬화 가능합니다.

  • 객체는 상위 클래스가 아닌 경우에도 직렬화 가능합니다(자체적으로 직렬화 가능 인터페이스를 구현함). 그러나 직렬화 가능 인터페이스를 구현하지 않는 직렬화 가능 클래스 계층의 첫 번째 수퍼클래스에는 인수가 없는 생성자가 있어야 합니다(MUST). 이를 위반하면 readObject()는 런타임에 java.io.InvalidClassException을 생성합니다.

  • 모든 기본 유형은 직렬화 가능합니다.

  • 일시적인 필드(transient modifier 포함)는 직렬화되지 않습니다(즉, 저장되거나 복원되지 않음). Serializable을 구현하는 클래스는 직렬화를 지원하지 않는 클래스의 임시 필드(예: 파일 스트림)를 표시해야 합니다.

  • 정적 필드(정적 수정자 포함)는 직렬화되지 않습니다.

Object 가 직렬화되면 Java Runtime은 직렬 버전 번호(일명 serialVersionID 합니다.

serialVersionID가 필요한 위치:

직렬화와 관련하여 발신자와 수신자가 호환되는지 확인하기 위해 역직렬화하는 동안. serialVersionID 로 클래스를 로드하면 역직렬화가 InvalidClassCastException 종료됩니다.
직렬화 가능 클래스는 static, final 및 long 유형이어야 하는 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() { 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()); } }

참고: 이제 Employee 클래스의 serialVersionUID를 변경하고 다음을 저장합니다.

 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)

JegsVala

객체를 바이트 배열로 직렬화하고 전송/저장할 필요가 없다면 걱정할 필요가 없습니다. 그렇게 하면 객체의 deserializer가 클래스 로더가 가지고 있는 객체 버전과 일치시키므로 serialVersionUID를 고려해야 합니다. 이에 대한 자세한 내용은 Java 언어 사양을 참조하십시오.


eishay

직렬화에 대해 생각하지 않은 클래스에서 이 경고가 표시되고 자신이 implements Serializable 선언하지 않았다면 이는 종종 직렬화를 구현하는 수퍼클래스에서 상속했기 때문입니다. 종종 상속을 사용하는 대신 그러한 객체에 위임하는 것이 더 나을 것입니다.

그래서, 대신

 public class MyExample extends ArrayList<String> { public MyExample() { super(); } ... }

~하다

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

그리고 관련 메소드에서 this.foo() (또는 super.foo() myList.foo() 를 호출합니다. (모든 경우에 해당되는 것은 아니지만 여전히 꽤 자주 사용됩니다.)

JFrame 등을 확장하는 사람들을 종종 봅니다. 실제로 이것에만 위임하면 됩니다. (JFrame에는 수백 개의 메서드가 있으므로 IDE에서 자동 완성에 도움이 됩니다. 클래스에서 사용자 지정 메서드를 호출할 때 필요하지 않습니다.)

경고(또는 serialVersionUID)가 불가피한 한 가지 경우는 일반적으로 익명 클래스에서 AbstractAction에서 확장하고 actionPerformed-method만 추가하는 경우입니다. 이 경우 경고가 없어야 한다고 생각하지만(일반적으로 클래스의 다른 버전에서 이러한 익명 클래스를 안정적으로 직렬화 및 역직렬화할 수 없기 때문에) 컴파일러가 이를 어떻게 인식할 수 있는지 잘 모르겠습니다.


Paŭlo Ebermann

serialVersionUID 필드의 중요성을 이해하려면 직렬화/역직렬화가 작동하는 방식을 이해해야 합니다.

Serializable 클래스 객체가 직렬화되면 Java Runtime은 직렬 버전 번호(serialVersionUID라고 함)를 이 직렬화된 객체와 연관시킵니다. 이 직렬화된 객체를 역직렬화할 때 Java 런타임은 직렬화된 객체의 serialVersionUID를 클래스의 serialVersionUID와 일치시킵니다. 둘 다 같으면 역직렬화의 추가 프로세스만 진행하고 그렇지 않으면 InvalidClassException이 발생합니다.

따라서 직렬화/역직렬화 프로세스가 성공하려면 직렬화된 객체의 serialVersionUID가 클래스의 serialVersionUID와 동일해야 한다는 결론을 내립니다. 프로그래머가 프로그램에서 명시적으로 serialVersionUID 값을 지정하는 경우 직렬화 및 역직렬화 플랫폼에 관계없이 동일한 값이 직렬화된 객체 및 클래스와 연관됩니다(예: 직렬화는 Windows와 같은 플랫폼에서 sun 또는 MS JVM 및 Deserialization은 Zing JVM을 사용하는 다른 플랫폼 Linux에 있을 수 있습니다.

그러나 프로그래머가 serialVersionUID를 지정하지 않은 경우 개체의 Serialization\DeSerialization을 수행하는 동안 Java 런타임은 자체 알고리즘을 사용하여 계산합니다. 이 serialVersionUID 계산 알고리즘은 JRE마다 다릅니다. 또한 객체가 직렬화되는 환경은 하나의 JRE(예: SUN JVM)를 사용하고 있고 역직렬화가 발생하는 환경은 Linux Jvm(zing)을 사용하고 있을 수도 있습니다. 이러한 경우 직렬화된 개체와 연결된 serialVersionUID는 역직렬화 환경에서 계산된 클래스의 serialVersionUID와 다릅니다. 차례로 역직렬화는 성공하지 못합니다. 따라서 이러한 상황/문제를 피하기 위해 프로그래머는 항상 Serializable 클래스의 serialVersionUID를 지정해야 합니다.


Nitesh Soni

누락된 serialVersionUID가 문제를 일으킬 수 있는 예:

EJB 모듈을 사용하는 웹 모듈로 구성된 이 Java EE 응용 프로그램에서 작업하고 있습니다. 웹 모듈은 원격으로 EJB 모듈을 호출하고 Serializable 을 구현 POJO 를 인수로 전달합니다.

POJO's 클래스는 웹 모듈의 WEB-INF/lib에 있는 EJB jar 내부와 자체 jar 내부에 패키징되었습니다. 그들은 실제로 같은 클래스이지만 EJB 모듈을 패키징할 때 이 POJO의 jar를 풀어 EJB 모듈과 함께 패키징합니다.

serialVersionUID EJB 에 대한 호출이 아래 예외와 함께 실패했습니다.

 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

Henrique Ordine

귀찮게하지 마십시오. 기본 계산은 정말 좋고 99,9999%의 경우에 충분합니다. 그리고 문제가 발생하면 이미 언급했듯이 필요에 따라 UID를 도입할 수 있습니다(가능성은 거의 없음)


grand johnson

나는 일반적으로 serialVersionUID 를 사용합니다. Java VM의 컨텍스트를 떠날 것임을 알 때.

ObjectInputStreamObjectOutputStream 을 사용할 때 또는 내가 사용하는 라이브러리/프레임워크를 알고 있는 경우 이를 사용할 것임을 알 수 있습니다. serialVersionID는 다양한 버전 또는 공급업체의 다른 Java VM이 올바르게 상호 운용되도록 하거나 예를 들어 HttpSession 과 같이 VM 외부에 저장 및 검색되는 경우 세션 데이터가 애플리케이션 서버를 다시 시작하고 업그레이드하는 동안에도 유지될 수 있도록 합니다.

다른 모든 경우에는 다음을 사용합니다.

 @SuppressWarnings("serial")

대부분의 경우 기본 serialVersionUID 로 충분하기 때문입니다. Exception , HttpServlet 이 포함됩니다.


Archimedes Trajano

필드 데이터는 클래스에 저장된 일부 정보를 나타냅니다. 클래스는 Serializable serialVersionUID 필드를 선언하도록 자동으로 제공됩니다. 거기에 설정된 값 1부터 시작하겠습니다.

해당 경고가 표시되지 않도록 하려면 다음을 사용하십시오.

 @SuppressWarnings("serial")

Mukti

SerialVersionUID는 개체의 버전 제어에 사용됩니다. 클래스 파일에서도 serialVersionUID를 지정할 수 있습니다. serialVersionUID를 지정하지 않으면 클래스의 필드를 추가하거나 수정할 때 새 클래스와 이전 직렬화된 개체에 대해 생성된 serialVersionUID가 다르기 때문에 이미 직렬화된 클래스를 복구할 수 없습니다. Java 직렬화 프로세스는 직렬화된 객체의 상태를 복구하기 위해 올바른 serialVersionUID에 의존하고 serialVersionUID가 일치하지 않는 경우 java.io.InvalidClassException을 발생시킵니다.

더 읽어보기: http://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html#ixzz3VQxnpOPZ


Coder123

CheckStyle이 Serializable을 구현하는 클래스의 serialVersionUID가 좋은 값을 가지고 있는지, 즉 직렬 버전 ID 생성기가 생성하는 것과 일치하는지 확인할 수 있다면 좋을 것입니다. 직렬화 가능한 DTO가 많은 프로젝트가 있는 경우, 예를 들어 기존 serialVersionUID를 삭제하고 다시 생성하는 것을 기억하는 것은 고통이며 현재 이를 확인하는 유일한 방법(내가 아는)은 각 클래스에 대해 다시 생성하고 비교하는 것입니다. 오래된 것. 이것은 매우 고통스럽습니다.


David Wright

Serializable 클래스 내에서 SerialVersionUID 사용하는 이유는 무엇입니까?

serialization 중에 Java 런타임은 나중에 역직렬화할 수 있도록 클래스에 대한 버전 번호를 생성합니다. 이 버전 번호는 Java에서 SerialVersionUID

SerialVersionUID 는 직렬화된 데이터의 버전을 지정하는 데 사용됩니다. SerialVersionUID 가 직렬화된 인스턴스와 일치하는 경우에만 클래스를 역직렬화할 수 있습니다. SerialVersionUID 를 선언하지 않으면 Java 런타임이 이를 생성하지만 권장하지는 않습니다. 기본 메커니즘을 피하기 위해 SerialVersionUIDprivate static final long 변수로 선언하는 것이 좋습니다.

마커 인터페이스 java.io.Serializable 을 구현하여 클래스를 Serializable Externalizable 인터페이스를 사용하여 프로세스를 사용자 정의하지 않은 경우 Java 런타임은 기본 직렬화 메커니즘을 사용하여 해당 클래스의 인스턴스를 디스크에 유지합니다.

Java의 Serializable 클래스 내에서 SerialVersionUID를 사용하는 이유 도 참조하십시오.


roottraveller

이전 클래스와의 호환성을 유지하면서 처음부터 serialVersionUID가 설정되지 않은 수많은 클래스를 수정하려는 경우 IntelliJ Idea, Eclipse와 같은 도구는 난수를 생성하고 많은 파일에서 작동하지 않기 때문에 부족합니다. 한 번에. serialVersionUID 문제를 쉽게 수정하기 위해 다음 bash 스크립트(Windows 사용자에게 죄송합니다. Mac을 구입하거나 Linux로 변환하는 것을 고려하십시오)를 제시합니다.

 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에는 다음 형식으로 serialVersionUID를 추가하기 위한 Java 파일 목록이 포함되어 있습니다.

 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에 있는지 확인하십시오.


schnell18

이 질문은 Joshua Bloch의 Effective Java에 매우 잘 설명되어 있습니다. 아주 좋은 책이고 꼭 읽어야 합니다. 아래에서 몇 가지 이유를 설명하겠습니다.

직렬화 런타임은 직렬화 가능한 각 클래스에 대해 직렬 버전이라는 번호를 제공합니다. 이 번호를 serialVersionUID라고 합니다. 이제 이 숫자 뒤에 약간의 수학이 있으며 클래스에 정의된 필드/메서드를 기반으로 나옵니다. 동일한 클래스에 대해 동일한 버전이 매번 생성됩니다. 이 번호는 직렬화와 관련하여 호환되는 해당 개체에 대해 로드된 클래스에 직렬화된 개체의 보낸 사람과 수신기가 있는지 확인하기 위해 역직렬화 중에 사용됩니다. 수신자가 해당 발신자의 클래스와 다른 serialVersionUID를 가진 객체에 대한 클래스를 로드한 경우 역직렬화로 인해 InvalidClassException이 발생합니다.

클래스가 직렬화 가능하면 정적이고 최종적이며 유형이 긴 "serialVersionUID"라는 필드를 선언하여 명시적으로 자신의 serialVersionUID를 선언할 수도 있습니다. Eclipse와 같은 대부분의 IDE는 긴 문자열을 생성하는 데 도움이 됩니다.


Geek

개체가 직렬화될 때마다 개체에는 개체 클래스의 버전 ID 번호가 찍힙니다. 이 ID를 serialVersionUID 라고 하며 클래스 구조에 대한 정보를 기반으로 계산됩니다. Employee 클래스를 만들고 버전 ID #333(JVM에 의해 할당됨)을 가지고 있다고 가정합니다. 이제 해당 클래스의 개체를 직렬화할 때(Employee 개체 가정), JVM은 UID를 #333으로 할당합니다.

상황을 고려하십시오. 미래에 클래스를 편집하거나 변경해야 하며 이 경우 클래스를 수정할 때 JVM이 새 UID를 할당합니다(가정 #444). 이제 직원 객체를 역직렬화하려고 하면 JVM은 직렬화된 객체(직원 객체) 버전 ID(#333)를 클래스(예: #444(변경된 이후))의 버전 ID와 비교합니다. 비교 시 JVM은 두 버전 UID가 모두 다르므로 직렬화 해제가 실패합니다. 따라서 각 클래스에 대한 serialVersionID가 프로그래머 자체에 의해 정의되는 경우입니다. 나중에 클래스가 진화하더라도 동일하므로 JVM은 클래스가 변경되더라도 직렬화된 객체와 항상 호환되는 클래스를 찾습니다. 자세한 내용은 HEAD FIRST JAVA의 14장을 참조하십시오.


Naved Ali

간단한 설명:

  1. 데이터를 직렬화하고 있습니까?

    직렬화는 기본적으로 클래스 데이터를 파일/스트림 등에 쓰는 것입니다. 역직렬화는 해당 데이터를 다시 클래스로 읽는 것입니다.

  2. 생산에 들어갈 의향이 있습니까?

    중요하지 않은/가짜 데이터로 무언가를 테스트하는 경우에는 그것에 대해 걱정하지 마십시오(직렬화를 직접 테스트하지 않는 한).

  3. 이게 첫 번째 버전인가요?

    serialVersionUID=1L 설정하십시오.

  4. 이것은 두 번째, 세 번째 등의 제품 버전입니까?

    serialVersionUID 에 대해 걱정해야 하며 깊이 살펴봐야 합니다.

기본적으로 쓰기/읽기가 필요한 클래스를 업데이트할 때 버전을 올바르게 업데이트하지 않으면 오래된 데이터를 읽으려고 하면 오류가 발생합니다.


gagarwa

'serialVersionUID'는 역직렬화 과정에서 클래스를 고유하게 식별하는 데 사용되는 64비트 숫자입니다. 개체를 직렬화하면 클래스의 serialVersionUID도 파일에 기록됩니다. 이 객체를 역직렬화할 때마다 Java 런타임은 직렬화된 데이터에서 이 serialVersionUID 값을 추출하고 클래스와 연결된 동일한 값을 비교합니다. 둘 다 일치하지 않으면 'java.io.InvalidClassException'이 발생합니다.

직렬화 가능한 클래스가 명시적으로 serialVersionUID를 선언하지 않으면 직렬화 런타임은 필드, 메서드 등과 같은 클래스의 다양한 측면을 기반으로 해당 클래스에 대한 serialVersionUID 값을 계산합니다. 데모 응용 프로그램에 대해서는 이 링크를 참조할 수 있습니다.


Hari Krishna

간단히 말해서 이 필드는 직렬화된 데이터가 올바르게 역직렬화될 수 있는지 확인하는 데 사용됩니다. 직렬화와 역직렬화는 종종 프로그램의 다른 복사본에 의해 만들어집니다. 예를 들어 서버는 객체를 문자열로 변환하고 클라이언트는 수신된 문자열을 객체로 변환합니다. 이 필드는 이 객체가 무엇인지에 대해 둘 다 동일한 아이디어로 작동함을 알려줍니다. 이 필드는 다음과 같은 경우에 도움이 됩니다.

  • 다른 위치(예: 1개의 서버 및 100개의 클라이언트)에 프로그램의 여러 복사본이 있습니다. 개체를 변경하고 버전 번호를 변경하고 이 클라이언트를 업데이트하는 것을 잊으면 역직렬화할 수 없다는 것을 알게 됩니다.

  • 데이터를 일부 파일에 저장하고 나중에 수정된 개체가 있는 프로그램의 업데이트된 버전으로 열려고 시도합니다. 버전을 올바르게 유지하면 이 파일이 호환되지 않는다는 것을 알게 될 것입니다.

언제 중요합니까?

가장 분명한 것은 개체에 일부 필드를 추가하면 개체 구조에 이러한 필드가 없기 때문에 이전 버전에서는 사용할 수 없다는 것입니다.

덜 명확함 - 개체를 역직렬화할 때 문자열에 없는 필드는 NULL로 유지됩니다. 객체에서 필드를 제거한 경우 이전 버전은 이 필드를 allways-NULL로 유지하여 이전 버전이 이 필드의 데이터에 의존하는 경우 오작동을 일으킬 수 있습니다(어쨌든 재미를 위해 생성한 것이 아니라 :-)).

최소한의 명백한 - 때때로 당신은 당신이 어떤 분야의 의미에 넣은 아이디어를 바꿉니다. 예를 들어, 12세일 때 "자전거" 아래에 있는 "자전거"를 의미하지만 18세일 때 "오토바이"를 의미합니다. 친구가 "도시를 가로지르는 자전거 타기"에 초대하고 귀하는 유일한 사람이 될 것입니다. 자전거를 타고 왔다면 여러 분야에서 같은 의미를 유지하는 것이 얼마나 중요한지 이해하게 될 것입니다 :-)


Stanislav Orlov

먼저 귀하의 질문에 답하기 위해 클래스에서 SerialVersionUID를 선언하지 않으면 Java 런타임이 이를 생성하지만 해당 프로세스는 필드 수, 필드 유형, 필드의 액세스 수정자, 구현된 인터페이스를 포함한 많은 클래스 메타 데이터에 민감합니다. 따라서 클래스 등으로 선언하는 것이 좋습니다. Eclipse는 이에 대해 경고합니다.

직렬화: 우리는 종종 상태(객체의 변수에 있는 데이터)가 너무 중요하여 객체 상태를 다른 객체로 보내는 경우 전원/시스템 장애(또는) 네트워크 장애로 인해 잃을 위험이 없는 중요한 객체로 작업합니다. 기계. 이 문제에 대한 솔루션은 "지속성"으로 명명되며 이는 단순히 데이터를 유지(보유/저장)하는 것을 의미합니다. 직렬화는 데이터를 디스크/메모리에 저장하여 지속성을 달성하는 다른 많은 방법 중 하나입니다. 객체의 상태를 저장할 때 객체에 대한 ID를 생성하여 제대로 다시 읽을 수 있도록 하는 것이 중요합니다(역직렬화). 이 고유 식별 ID는 SerialVersionUID입니다.


Shanks D Shiva

SerialVersionUID란 무엇입니까? 답변 : - HQ와 ODC의 두 사람이 각각 직렬화와 역직렬화를 수행한다고 가정해 보겠습니다. 이 경우 ODC에 있는 수신자가 인증된 사람인지 인증하기 위해 JVM은 SerialVersionUID라는 고유 ID를 생성합니다.

다음은 시나리오를 기반으로 한 멋진 설명입니다.

왜 SerialVersionUID인가?

직렬화 : 직렬화 시 모든 객체 발신자 측 JVM은 고유 식별자를 저장합니다. JVM은 발신자 시스템에 있는 해당 .class 파일을 기반으로 고유 ID를 생성할 책임이 있습니다.

역직렬화 : 역직렬화 시 수신기 측 JVM은 객체와 연결된 고유 ID를 로컬 클래스 고유 ID와 비교합니다. 즉 JVM은 수신기 시스템에 있는 해당 .class 파일을 기반으로 고유 ID도 생성합니다. 두 고유 ID가 모두 일치하면 역직렬화만 수행됩니다. 그렇지 않으면 InvalidClassException이라는 런타임 예외가 발생합니다. 이 고유 식별자는 SerialVersionUID에 불과합니다.


forkdbloke

출처 : http:www.stackoverflow.com/questions/285793/what-is-a-serialversionuid-and-why-should-i-use-it

반응형