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

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

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

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



답변

에 대한 문서 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필드 에만 적용되므로 상속 된 멤버로는 유용하지 않으므로 가능한 경우 개인 수정자를 사용합니다 .


답변

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

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

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


답변

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

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

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


답변

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

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

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

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

그리고 더 많은.


답변

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

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

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

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

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

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

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

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

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


답변

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

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

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

에 대한 JavaDoc을Serializable :

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

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

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


답변

원래의 질문은 이것이 중요한 이유와 ‘예’에 대해 물었습니다 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
}