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


2999

serialVersionUID이 없으면 Eclipse가 경고를 발행 합니다.

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

무엇 serialVersionUID이며 왜 중요합니까? 누락으로 serialVersionUID인해 문제가 발생 하는 예를 보여주십시오 .


1
serialversionUID에 대한 모범 사례를 찾으십시오. dzone.com/articles/what-is-serialversionuid
ceyun

답변:


2290

에 대한 문서 java.io.Serializable는 아마도 당신이 얻는만큼 좋은 설명 일 것입니다.

직렬화 런타임 serialVersionUID은 직렬화 가능 오브젝트의 송신자 및 수신자가 직렬화와 호환되는 해당 오브젝트에 대한 클래스를로드했는지 검증하기 위해 직렬화 해제 중에 사용되는 버전 번호 인 버전 번호를 각 직렬화 가능 클래스와 연관시킵니다 . 수신자가 serialVersionUID해당 발신자의 클래스와 다른 객체의 클래스를로드 한 경우 역 직렬화는을 발생 InvalidClassException시킵니다. 직렬화 가능 클래스는 static, final 및 type이어야 serialVersionUID하는 필드를 선언하여 명시 적으로 자체 선언 할 수 있습니다 .serialVersionUIDlong

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

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


325
따라서 본질적으로 말하는 것은 사용자가 위의 모든 자료를 이해하지 못하면 직렬화에 대해 걱정할 필요가 없다는 것입니다. 당신이 "어떻게?" "왜?"를 설명하기보다는 나는 왜 SerializableVersionUID를 귀찮게했는지 이해하지 못합니다.
Ziggy

365
두 번째 단락에 이유가 있습니다. serialVersionUID를 명시 적으로 지정하지 않으면 값이 자동으로 생성되지만 컴파일러 구현에 따라 달라지기 쉽습니다.
Jon Skeet

14
그리고 왜 Eclipse가 "개인 정적 최종 long serialVersionUID = 1L;"이 필요하다고 말합니까? 예외 클래스를 확장하면
JohnMerlino

21
@ JohnMerlino : 글쎄, 당신이 그것을 필요 로한다고 생각하지는 않을 것입니다. 그러나 예외를 올바르게 직렬화하는 것을 돕기 위해 제안 할 수도 있습니다 . 직렬화하지 않으려는 경우 실제로 상수가 필요하지 않습니다.
Jon Skeet 2016 년

16
@JohnMerlino, 귀하의 질문 부분에 대한 답변 : 예외는 Serializable을 구현하고 EclipseSerialVersionUID를 설정하지 않았다는 경고를 표시합니다. 요점.
zpon

475

구현을 위해 직렬화해야하기 때문에 직렬화하는 경우 ( HTTPSession예를 들어 직렬화를 신경 쓰는 사람은 저장하거나하지 않으면 de-serializing양식 객체에 신경 쓰지 않을 것입니다 ) 이것을 무시하십시오.

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

대부분의 경우 직렬화를 직접 사용하지 않을 것입니다. 이 경우 SerialVersionUID빠른 수정 옵션을 클릭하여 기본값 을 생성하고 걱정하지 마십시오.


78
영구 저장소에 직렬화를 사용하지 않는 경우 값을 추가하는 대신 @SuppressWarnings를 사용해야합니다. 클래스를 덜 어지럽게 만들고 serialVersionUID 메커니즘의 기능을 유지하여 호환되지 않는 변경으로부터 보호합니다.
Tom Anderson

25
다른 줄 (직렬화 가능한 ID)과 반대로 한 줄 (@SuppressWarnings 주석)을 추가하는 것이 "클래스를 덜 어지럽히는"방법을 보지 못했습니다. 영구 저장을 위해 직렬화를 사용하지 않는다면 왜 "1"을 사용하지 않습니까? 이 경우 자동 생성 된 ID는 신경 쓰지 않아도됩니다.
MetroidFan2002

71
@ MetroidFan2002 : @TomAnderson이 serialVersionUID호환되지 않는 변경으로부터 사용자를 보호하는 것이 타당 하다고 생각 합니다. 사용 @SuppressWarnings하면 영구 저장을위한 클래스를 사용하지 않으려면 의도 나은 문서를.
AbdullahC

11
"현재 클래스의 클래스가 이전 버전과 호환되지 않는 경우이를 증가시켜야합니다."먼저 직렬화에 대한 광범위한 객체 버전 관리 지원을 탐색해야합니다. 사양에 따라 달성하기가 매우 어렵습니다. (b) 사용자 정의 read / writeObject () 메소드, readResolve / writeReplace () 메소드, serializableFields 선언 등과 같은 스킴을 시도하여 스트림이 호환 가능한지 확인하십시오. 실제를 바꾸는 것은 serialVersionUID절망의 조언 인 최후의 수단입니다.
user207421

4
@EJP serialVersionUID의 증가는 클래스의 초기 작성자가 명시 적으로 소개했을 때 나타납니다 .jvm 생성 직렬 ID는 괜찮을 것입니다. 이것은 직렬화에서 본 최고의 답변 입니다.
overexchange

307

Josh Bloch의 책 Effective Java (2nd Edition) 를 연결하는 기회를 전달할 수 없습니다 . 11 장은 Java 직렬화에 없어서는 안될 리소스입니다.

Josh에 따라 자동 생성 된 UID는 클래스 이름, 구현 된 인터페이스 및 모든 공개 및 보호 된 멤버를 기반으로 생성됩니다. 어떤 방법 으로든 이들을 변경하면가 변경됩니다 serialVersionUID. 따라서 하나 이상의 버전의 클래스가 직렬화 될 것이라고 확신하는 경우에만 프로세스와 충돌하거나 나중에 스토리지에서 검색 할 수 있습니다.

지금은 무시하고 나중에 클래스를 변경해야하지만 이전 버전의 호환성을 유지해야한다는 것을 나중에 발견하면 JDK 도구 serialver 를 사용 serialVersionUID하여 이전 클래스에서 생성 하고 명시 적으로 설정할 수 있습니다 새로운 수업에. (변경 사항에 따라 추가 writeObjectreadObject메소드를 통해 사용자 정의 직렬화를 구현해야 할 수도 있습니다. Serializablejavadoc 또는 11 장을 참조하십시오 .)


33
따라서 이전 버전의 클래스와의 호환성이 염려되면 SerializableVersionUID를 사용하지 않아도 될까요?
Ziggy

10
따라서 최신 버전에서 공개 멤버를 protected로 변경하면 기본 SerializableVersionUID가 달라지고 InvalidClassExceptions가 발생합니다.
Chander Shivdasani

3
클래스 이름, 구현 된 인터페이스, 모든 공용 및 보호 된 메소드, 모든 인스턴스 변수.
Achow

31
Joshua Bloch는 모든 Serializable 클래스에 대해 직렬 버전 uid를 지정하는 것이 좋습니다. 11 장의 인용문 : 어떤 직렬화 형식을 선택하든, 작성하는 모든 직렬화 가능 클래스에서 명시 적 직렬 버전 UID를 선언하십시오. 이로 인해 직렬 버전 UID가 잠재적 인 비 호환성 원인이됩니다 (항목 74). 작은 성능 이점도 있습니다. 직렬 버전 UID가 제공되지 않으면 런타임시 UID를 생성하려면 값 비싼 계산이 필요합니다.
Ashutosh Jindal

136

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

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

모르는 경우이 섹션에서 활성화 할 수있는 다른 많은 경고가 있거나 오류로보고 된 경우가 많으며, 그 중 많은 것이 매우 유용합니다.

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

그리고 더 많은.


21
원본 포스터가 아무 것도 직렬화하지 않는 것처럼 보이기 만합니다. 포스터는 "내가 ...이 일을 직렬화하고있어"라고하면 당신은 아래로 대신 투표를 얻을 것입니다 : P
존 가드너

3
사실 – 나는 질문자에게 단순히 경고하고 싶지 않다고 가정했다
matt b

14
@Gardner-> 동의했습니다! 그러나 질문자는 또한 왜 경고를 원하지 않는지 알고 싶어합니다.
Ziggy

8
질문자는 분명히 UID가 필요한 이유에 관심을 갖습니다. 따라서 단순히 경고를 무시하라고 지시하는 것은 무시해야합니다.
cinqS

111

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

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

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

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

이 경우 이전 버전과의 호환성 유지에 관심이 없습니다. 실제로 통신하는 코드베이스가 동일한 버전의 관련 클래스를 갖는지 확인하는 데에만 관심이 있습니다. 이러한 점검을 용이하게하기 위해서는 serialVersionUID이전과 마찬가지로 유지하고 클래스를 변경할 때이를 업데이트하는 것을 잊지 않아야합니다.

필드를 업데이트하는 것을 잊어 버린 경우 구조는 다르지만 동일한 두 가지 버전의 클래스가 생길 수 있습니다 serialVersionUID. 이 경우 기본 메커니즘 ( in.defaultReadObject())은 차이를 감지하지 않으며 호환되지 않는 데이터를 직렬화 해제하려고합니다. 이제 암호 런타임 오류 또는 자동 실패 (널 필드)가 발생할 수 있습니다. 이러한 유형의 오류는 찾기 어려울 수 있습니다.

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

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

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


4
일시적이지 않은 필드를 추가하거나 제거해도 클래스 직렬화가 호환되지 않습니다. 그러므로 그러한 변화에 '충돌'할 이유가 없습니다.
user207421

4
@EJP : 응? 데이터를 추가하면 분명히 내 세계의 직렬화 데이터가 변경됩니다.
Alexander Torstling

3
@AlexanderTorstling 내가 쓴 것을 읽으십시오. 나는 그것이 직렬화 데이터를 변경하지 않는다고 말하지 않았다. 나는 그것이 클래스 직렬화를 비호 환적이지 않았다고 말했다. 같은 것이 아닙니다. Object Serialization Specification의 버전 관리 장을 읽어야합니다.
user207421

3
@ EJP : 일시적이지 않은 필드를 추가한다고해서 클래스 직렬화가 호환되지 않는다는 것을 의미하지는 않지만 직렬화 된 데이터를 변경하는 구조적 변경이므로 일반적으로 그렇지 않으면 버전을 충돌시키고 싶습니다. 이전 버전과의 호환성을 다루기 때문에 나중에 포스트에서 설명했습니다. 요점이 정확히 무엇입니까?
Alexander Torstling

4
내 요점은 내가 한 말 그대로입니다. 일시적이지 않은 필드를 추가하거나 제거해도 클래스 직렬화가 호환되지 않습니다. 따라서 serialVersionUID를 사용할 때마다 충돌 할 필요는 없습니다.
user207421

72

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

SerialVersionUID는 각 클래스의 고유 식별자로, JVM직렬화 중에 동일한 클래스가 사용되어 직렬화 해제 중에로드되도록 클래스의 버전을 비교하는 데 사용합니다.

하나를 지정하면 더 많은 제어가 가능하지만 지정하지 않으면 JVM이 하나를 생성합니다. 생성 된 값은 컴파일러마다 다를 수 있습니다. 또한 어떤 이유로 인해 오래된 직렬화 된 객체 [ backward incompatibility]의 역 직렬화를 금지하려는 경우가 있습니다.이 경우 serialVersionUID 만 변경하면됩니다.

에 대한 JavaDoc을Serializable :

기본 serialVersionUID 계산은 컴파일러 구현에 따라 달라질 수있는 클래스 세부 정보에 매우 민감하므로 InvalidClassException역 직렬화 중에 예기치 않은 결과가 발생할 수 있습니다 .

따라서 serialVersionUID는 더 많은 제어권을 부여하므로 선언해야합니다 .

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


3
@Vinothbabu이지만 serialVersionUID는 정적이므로 정적 변수를 직렬화 할 수 없습니다. jvm은 deserializing 객체의 버전이 무엇인지 모른 채 버전을 확인하는 방법
Kranthi Sama

3
이 답변에 언급되지 않은 한 가지 serialVersionUID이유는 이유를 모른 채 맹목적으로 포함함으로써 의도하지 않은 결과를 초래할 수 있다는 것 입니다. MetroidFan2002의 답변에 대한 Tom Anderson의 의견은 다음과 같이 설명합니다. "영구 스토리지에 직렬화를 사용하지 않는 경우 값을 추가하는 대신 @SuppressWarnings를 사용해야합니다. 클래스를 덜 어지럽게하고 호환되지 않는 변경으로부터 사용자를 보호하는 serialVersionUID 메커니즘. "
커비

7
serialVersionUID'각 클래스의 고유 식별자' 가 아닙니다 . 정규화 된 클래스 이름입니다. 그것은이다 버전 표시.
user207421

58

원래의 질문은 이것이 중요한 이유와 '예'에 대해 물었습니다 Serial Version ID. 글쎄, 나는 하나를 발견했다.

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

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

그리고 모든 UID에 1L이 아닌 임의의 긴 숫자를 할당해야합니다.
abbas

4
@abbas 'One should'그런 이유는 무엇입니까? 차이점이 무엇인지 설명하십시오.
user207421

이름에서 알 수 있듯이 객체를 직렬화하는 데 사용 된 클래스 버전을 나타냅니다. 매번 같은 번호를 할당하면 직렬화 해제에 적합한 클래스를 찾을 수 없습니다. 따라서 수업을 변경할 때마다 버전도 변경하는 것이 좋습니다.
abbas

2
@abbas,이 의도는 증가하는 자연수 등을 사용하여 충돌하지 않습니다 1.
Vadzim

2
@ BillK, 직렬화 검사가 클래스 이름과 serialVersionUID 쌍에 바인딩되어 있다고 생각했습니다. 따라서 다른 클래스와 라이브러리의 다른 번호 체계는 어떤 식 으로든 방해 할 수 없습니다. 아니면 코드 생성 라이브러리를 암시 했습니까?
Vadzim

44

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

직렬화를 사용하면 네트워크를 통해 해당 오브젝트를 전송하거나 파일에 저장하거나 문자 사용을 위해 DB에 저장할 수 있도록 오브젝트를 스트림으로 변환 할 수 있습니다.

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

  • 클래스 또는 수퍼 클래스가 Serializable 인터페이스를 구현하는 경우에만 객체를 직렬화 할 수 있습니다

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

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

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

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

Object직렬화, 자바 런타임은이 일련 버전 번호 일명 연결합니다 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() {
    StringBuffer employee = new StringBuffer();
    employee.append(getEmpName()).append(" is ).append(getEmpAge()).append("
years old  "));
    return employee.toString();
}
}

직렬화 객체 생성

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)

내가 틀렸다면 수정하십시오-로컬 클래스는 현재 클래스 경로에서 사용하고있는 클래스이고 스트림은 다른 당사자가 사용하는 클래스입니다 (예 : 답을 반환하고 서버를 직렬화 한 서버 응답). 타사 라이브러리를 업데이트 한 서버와 통신 할 때이 상황이 발생할 수 있지만 사용자 (클라이언트)는이 작업을 수행하지 않았습니다.
Victor

37

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


10
객체를 직렬화하지 않을 경우 왜 직렬화 할 수 있습니까?
erickson

7
@erickson-부모 클래스는 ArrayList와 같은 직렬화 가능하지만 자신의 객체 (예 : 수정 된 배열 목록)를 기본으로 사용하기를 원하지만 생성 한 Collection을 직렬화하지는 않습니다.
MetroidFan2002

5
Java 언어 사양의 어느 곳에서도 언급되지 않았습니다. Object Versioning Specification에 언급되어 있습니다.
user207421

4
다음은 Java 8 Object Versioning Specification에 대한 링크 입니다.
Basil Bourque

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이나 그와 같은 것을 확장 해야하는 경우가 종종 있습니다. JFrame에는 수백 가지의 메소드가 있으므로 클래스에서 사용자 정의 메소드를 호출하려고 할 때 필요하지 않으므로 IDE에서 자동 완성에 도움이됩니다.

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


4
특히 ArrayList와 같은 클래스를 논의 할 때 무너짐에 대한 구성이 더 합리적이라고 생각합니다. 그러나 많은 프레임 워크에서는 직렬화 가능한 (예 : Struts 1.2의 ActionForm 클래스 또는 Saxon의 ExtensionFunctionDefinition과 같은) 추상 수퍼 클래스에서 확장해야하는 경우이 솔루션을 실행할 수 없습니다. 나는 당신이 옳다고 생각합니다 (추상 직렬화 가능 클래스에서 확장하는 경우와 같은) 특정 경우에 경고가 무시되면 좋을 것입니다
piepera

2
클래스를 상속하지 않고 멤버로 클래스를 추가하는 경우, 사용하려는 멤버 클래스의 모든 메소드에 대해 랩퍼 메소드를 작성해야하므로 많은 상황에서 클래스를 사용할 수 없습니다. java가 perl 's와 비슷한 기능을 가지고 __AUTOLOAD있지 않으면 알 수 없습니다.
M_M

4
@M_M : 랩핑 된 객체에 많은 메소드를 위임 할 때는 물론 위임을 사용하는 것이 적절하지 않습니다. 그러나이 경우는 디자인 실수의 징후라고 생각합니다. 클래스 사용자 (예 : "MainGui")는 래핑 된 객체 (예 : JFrame)의 많은 메소드를 호출 할 필요가 없습니다.
Paŭlo Ebermann

1
위임에 대해 내가 싫어하는 것은 대리인에 대한 참조를 보유해야한다는 것입니다. 그리고 모든 참조는 더 많은 메모리를 의미합니다. 틀 렸으면 말해줘. 100 개체의 CustomizedArrayList가 필요한 경우에는 그다지 중요하지 않지만 몇 가지 개체의 수백 개의 CustomizdeArrayList가 필요하면 메모리 사용량이 크게 증가합니다.
WVrock

2
Throwable은 직렬화 가능하고 Throwable 만 throw 가능하므로 직렬화 가능하지 않은 예외를 정의 할 수 없습니다. 위임이 불가능합니다.
Phil

22

serialVersionUID 필드의 중요성을 이해하려면 Serialization / Deserialization 작동 방식을 이해해야합니다.

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

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

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


2
알고리즘은 다양하지 않지만 약간 지정되지 않았습니다.
user207421

... 알고리즘이 변화하지 않지만, 아래에 지정된 약간은 ... 어떤 JVM을 의미하는 것은 다를 수 있습니다 ..... @ user207421
AnthonyJClink

18

걱정하지 마십시오. 기본 계산은 실제로 훌륭하고 99,9999 %의 경우 충분합니다. 그리고 문제가 발생하면 이미 언급했듯이 필요에 따라 UID를 도입 할 수 있습니다.


2
쓰레기. 수업이 바뀌지 않은 경우에 적합합니다. '99 .9999 % '를 지원할 증거가 없습니다.
user207421

18

누락 된 serialVersionUID가 문제를 일으킬 수있는 예는 다음과 같습니다.

모듈을 사용하는 웹 모듈로 구성된이 Java EE 애플리케이션을 작업 중입니다 EJB. 웹 모듈은 EJB모듈을 원격으로 호출하고 인수로 POJO구현 되는를 전달합니다 Serializable.

POJO's클래스는 EJB jar 내부와 웹 모듈의 WEB-INF / lib에있는 자체 jar 내부에 패키지되었습니다. 그것들은 실제로 같은 클래스이지만 EJB 모듈을 패키지 할 때이 POJO의 jar를 풀어서 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

16

나는 일반적으로 serialVersionUID하나의 컨텍스트에서 사용합니다 . 알면 Java VM의 컨텍스트를 떠날 것입니다.

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

다른 모든 경우에는

@SuppressWarnings("serial")

대부분의 경우 기본값 serialVersionUID으로 충분합니다. 여기에는 Exception, HttpServlet.


스왑 아웃 할 수있는 컨테이너에는 HttpServlet이 포함되어 있지 않으며 RMI에서는 예외가 있습니다.
user207421

14

필드 데이터는 클래스에 저장된 일부 정보를 나타냅니다. 클래스는 Serializable인터페이스를 구현 하므로 serialVersionUID필드 를 선언하기 위해 Eclipse가 자동으로 제공됩니다 . 값 1을 설정하여 시작하겠습니다.

경고가 표시되지 않게하려면 다음을 사용하십시오.

@SuppressWarnings("serial")

11

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


8
serialVersionUID를 항상 생성기와 동일한 값으로 설정하면 실제로 필요하지 않습니다. 결국, 클래스의 호환성은 클래스가 여전히 호환되는 경우 변경 후에도 동일하게 유지됩니다.
Paŭlo Ebermann 2019

4
그 이유는 다른 컴파일러가 동일한 클래스에 대해 동일한 값을 갖기 때문입니다. javadocs (위에서 답변)에서 설명했듯이 생성 된 버전은 부서지기 쉽고 클래스가 올바르게 직렬화 해제 될 때도 달라질 수 있습니다. 매번 동일한 컴파일러에서이 테스트를 실행하는 한 안전합니다. 코드가 변경되지 않았어도 jdk를 업그레이드하고 새로운 규칙이 나오면 신이 도와줍니다.
Andrew Backer

2
serialver생산하는 것과 일치 할 필요는 없습니다 . -1
user207421

일반적으로 전혀 필요하지 않습니다. @AndrewBacker의 경우 두 버전의 .class 파일이 서로 통신하는 동일한 .java 파일에 서로 다른 두 개의 컴파일러가 필요합니다. 대부분 클래스를 만들고 배포하면됩니다. 이 경우 SUID가 없으면 정상적으로 작동합니다.
Bill K

1
저장 / 검색 목적으로 직렬화를 실제로 사용하는 사용자는 일반적으로 1로 설정합니다 serialVersionUID. 최신 버전의 클래스가 호환되지 않지만 여전히 이전 데이터를 처리 할 수 ​​있어야하는 경우 버전 번호를 늘리고 특수 코드를 추가합니다. 오래된 형식을 다룹니다. 나는 serialVersionUID1 자리보다 큰 숫자를 볼 때마다 , 그것은 임의의 숫자 (무효)이거나 수업이 분명히 10 가지 이상의 다른 버전을 처리해야하기 때문에 울었 습니다.
john16384

11

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

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


9

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

동안 serializationJava 런타임은 클래스의 버전 번호를 작성하여 나중에 직렬화 해제 할 수 있습니다. 이 버전 번호는 SerialVersionUIDJava 로 알려져 있습니다 .

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

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

또한 참조 사용 Java로 내부 직렬화 가능 클래스의 serialVersionUID 이유

코드 : javassist.SerialVersionUID


8

이전 버전의 IntelliJ Idea와 같은 도구와의 호환성을 유지하면서 serialVersionUID가 설정되지 않은 수많은 클래스를 수정하려는 경우 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에 있는지 확인하십시오.


2
나에게 아이디어를 제공합니다 : 릴리스하기 전에 항상 손으로 절대로 이와 같은 도구로 직렬 버전 uid를 재생성하십시오-그렇게하면 실제 버전 때문에 uid가 변경되어야하는 클래스를 변경하는 것을 잊어 버릴 수 있습니다 호환되지 않는 변경. 수동으로 추적하는 것은 매우 어렵습니다.
Ignazio

6

이 질문은 Joshua Bloch의 Effective Java에 잘 설명되어 있습니다. 아주 좋은 책과 필독서. 아래에 몇 가지 이유를 설명하겠습니다.

직렬화 런타임은 각 직렬화 가능 클래스에 대해 직렬 버전이라는 숫자를 제공합니다. 이 번호를 serialVersionUID라고합니다. 이제이 숫자 뒤에 약간의 수학이 있으며 클래스에 정의 된 필드 / 방법을 기반으로합니다. 동일한 클래스에 대해 매번 동일한 버전이 생성됩니다. 이 숫자는 직렬화 해제 중에 직렬화 된 오브젝트의 송신자와 수신자가 직렬화와 호환되는 해당 오브젝트에 대한 클래스를로드했는지 확인하는 데 사용됩니다. 수신자가 해당 발신자의 클래스와 다른 serialVersionUID를 가진 객체에 대한 클래스를로드 한 경우 역 직렬화는 InvalidClassException을 발생시킵니다.

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


6

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

상황을 고려하십시오-나중에 클래스를 편집하거나 변경해야하며,이 경우 클래스를 수정하면 JVM에 새 UID (공급 번호 444)가 지정됩니다. 이제 직원 객체를 직렬화 해제하려고하면 JVM은 직렬화 된 객체의 (직원 개체) 버전 ID (# 333)를 클래스의 # 444 (변경 된 이후)와 비교합니다. 비교하면 JVM은 두 버전의 UID가 다르므로 역 직렬화가 실패합니다. 따라서 각 클래스의 serialVersionID가 프로그래머 자체에 의해 정의되는 경우. 나중에 클래스가 발전하더라도 동일하므로 JVM은 클래스가 변경 되어도 클래스가 직렬화 된 객체와 호환된다는 것을 항상 알게 될 것입니다. 자세한 정보는 HEAD FIRST JAVA의 14 장을 참조하십시오.


1
객체 의 클래스 가 직렬화 될 때마다 serialVersionUID전송됩니다. 모든 객체와 함께 전송되는 것은 아닙니다.
user207421

3

간단한 설명 :

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

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

  2. 생산을 시작 하시겠습니까?

    중요하지 않은 / 가짜 데이터로 무언가를 테스트하는 경우 직렬화를 직접 테스트하지 않는 한 걱정하지 않아도됩니다.

  3. 이것이 첫 번째 버전입니까?

    그렇다면을 설정하십시오 serialVersionUID=1L.

  4. 이것이 두 번째, 세 번째 등의 자극적 인 버전입니까?

    이제 걱정할 필요가 serialVersionUID있으며 자세히 살펴 봐야합니다.

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


2

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

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


1

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

  • 서로 다른 위치에 1 개의 서버와 100 개의 클라이언트와 같은 여러 프로그램 사본이 있습니다. 객체를 변경하고 버전 번호를 변경하고이 클라이언트를 업데이트하는 것을 잊어 버린 경우에는 직렬화 해제 할 수 없다는 것을 알게됩니다.

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

언제 중요합니까?

가장 명백한-객체에 일부 필드를 추가하면 객체 구조에 이러한 필드가 없기 때문에 이전 버전에서는 해당 필드를 사용할 수 없습니다.

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

가장 눈에 띄지 않음-때로는 필드의 의미에 대한 아이디어를 변경합니다. 예를 들어, 12 세인 경우 "자전거"아래에서 "자전거"를 의미하지만 18 세인 경우 "오토바이"를 의미합니다. 친구가 "도시를 가로 질러 자전거 타기"에 초대하면 유일한 사람이됩니다. 자전거에 와서, 당신은 여러 분야에서 동일한 의미를 유지하는 것이 얼마나 중요한지 이해할 것입니다 :-)


1

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

직렬화 : 우리는 종종 상태 (객체의 변수에있는 데이터)가 매우 중요한 중요한 객체를 다루며, 객체 상태를 다른 사람에게 보낼 때 전원 / 시스템 장애 (또는 네트워크 장애)로 인해 데이터를 잃을 위험이 없습니다. 기계. 이 문제에 대한 해결책을 "지속성"이라고하며 이는 단순히 데이터를 유지 (보유 / 저장)하는 것을 의미합니다. 직렬화는 데이터를 디스크 / 메모리에 저장하여 지속성을 달성하는 다른 많은 방법 중 하나입니다. 객체의 상태를 저장할 때 객체를 제대로 읽을 수 있도록 객체의 ID를 생성하는 것이 중요합니다 (직렬화 해제). 이 고유 ID는 ID가 SerialVersionUID입니다.


0

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

시나리오를 기반으로 한 좋은 설명이 있습니다.

왜 SerialVersionUID인가?

직렬화 : 직렬화 시 모든 오브젝트 송신자 측 JVM이 고유 식별자를 저장합니다. JVM은 발신자 시스템에있는 해당 .class 파일을 기반으로 고유 한 ID를 생성해야합니다.

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.