UFO ET IT

Java 직렬화-java.io.InvalidClassException 로컬 클래스가 호환되지 않습니다.

ufoet 2020. 12. 30. 08:31
반응형

Java 직렬화-java.io.InvalidClassException 로컬 클래스가 호환되지 않습니다.


이 질문에 이미 답변이 있습니다.

다른 여러 클래스에 의해 확장 된 Serializable을 구현하는 공용 클래스가 있습니다. 이전에는 해당 하위 클래스 만 직렬화되었습니다. 수퍼 클래스는 아닙니다.

수퍼 클래스는 serialVersionUID를 정의했습니다.

중요한지 확실하지 않지만 비공개로 표시되지 않고 기본 보호 기능이 있습니다. 패키지 보호라고 말할 수 있습니다.

static final long serialVersionUID = -7588980448693010399L;

그러나 수퍼 클래스 또는 하위 클래스는 readObject 또는 writeObject를 구현했으며 어떤 하위 클래스에도 명시 적으로 정의 된 serialVersionUID가 없습니다. 나는 수퍼 클래스에 정의 된 것이 충분할 것이라고 생각했습니다.

이 모든 것에도 불구하고 새로운 인스턴스 변수 인 List / ArrayList와 함께 새로운 메서드가 수퍼 클래스에 추가되고 일부 개인 인스턴스 변수가 하위 클래스 중 하나에 추가 될 때까지 이전에 직렬화 된 객체를 다시 읽는 한 괜찮 았습니다. .

이제 이전에 직렬화 된 객체를 다시 읽으려고 할 때 예외가 발생합니다. 이것과 비슷한 것 :

com.SomeCompany.SomeSubClass; local class incompatible: stream classdesc serialVersionUID = 1597316331807173261, local class serialVersionUID = -3344057582987646196

하위 클래스 중 하나를 선언하지 않았기 때문에 사용 된 기본 serialVersionUID가 수퍼 클래스와 하나의 하위 클래스의 변경으로 인해 변경 되었기 때문에 이것이 발생했다고 가정합니다.

이 딜레마에서 벗어나는 방법에 대한 제안을 주시면 감사하겠습니다. readObject 및 writeObject를 구현해야한다고 가정하고 있지만 defaultReadObject () 및 defaultWriteObject ()를 호출하는 것 외에는 정확히 무엇을해야하는지 잘 모르겠습니다. 또한 모든 하위 클래스에 serialVerisonUID를 추가해야하는지 또는 각 하위 클래스에서 readObject 및 writeObject를 구현해야하는지 또는 수퍼 클래스에서 필요하다고 가정하여 한 번만 구현할 수 있는지도 알 수 없습니다.


@DanielChapman 은 serialVersionUID에 대한 좋은 설명을 제공하지만 해결책은 없습니다. 해결책은 이것입니다 : serialver모든 이전 클래스 에서 프로그램을 실행하십시오 . serialVersionUID값을 현재 버전의 클래스 에 넣으십시오 . 현재 클래스가 이전 버전과 직렬 호환되는 한 괜찮습니다. (미래의 코드에 대한 참고 사항 : 당신이해야 항상serialVersionUID에 대한 모든 Serializable 클래스)

새 버전이 직렬 호환 되지 않는 경우 사용자 정의 readObject구현으로 마법을 수행해야합니다 ( 이전 코드와 호환되는 클래스 데이터 writeObject를 작성하려는 경우 에만 사용자 정의가 필요합니다 ). 일반적으로 클래스 필드를 추가하거나 제거해도 클래스 직렬이 호환되지 않는 것은 아닙니다. 일반적으로 기존 필드의 유형을 변경합니다.

물론 새 클래스 직렬 호환 가능 하더라도 사용자 정의 readObject구현을 원할 수 있습니다 . 이전 버전의 클래스에서 저장된 데이터에서 누락 된 새 필드를 채우려면이 옵션을 원할 수 있습니다 (예 : 이전 클래스 데이터를로드 할 때 빈 목록으로 초기화하려는 새 목록 필드가 있음).


여기서 짧은 대답은 직렬 ID가 지정하지 않으면 해시를 통해 계산된다는 것입니다. (정적 멤버는 상속되지 않습니다. 정적 멤버이며 (1) 만 있고 클래스에 속합니다).

http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html

getSerialVersionUID 메서드는이 클래스의 serialVersionUID를 반환합니다. 4.6 절. "스트림 고유 식별자"를 참조하십시오. 클래스에서 지정하지 않은 경우 반환되는 값은 National Institute of Standards에서 정의한 SHA (Secure Hash Algorithm)를 사용하여 클래스의 이름, 인터페이스, 메서드 및 필드에서 계산 된 해시입니다.

클래스 또는 계층 구조를 변경하면 해시가 달라집니다. 이것은 좋은 일입니다. 이제 개체는 멤버가 다르기 때문에 다릅니다. 따라서 직렬화 된 형식에서 다시 읽어 들이면 실제로는 다른 개체이므로 예외입니다.

긴 대답은 직렬화가 매우 유용하지만 다른 방법이없는 한 지속성을 위해 사용해서는 안된다는 것입니다. 특히 당신이 경험하고있는 것 때문에 위험한 길입니다. 순수한 Java 프로젝트를위한 데이터베이스, XML, 파일 형식 및 JPA 또는 기타 지속성 구조를 고려해야합니다.


나를 위해 기본 일련 ID를 추가하는 것을 잊었습니다.

private static final long serialVersionUID = 1L;

이것은 나를 위해 일했습니다.

Serialized 클래스 객체를 파일에 작성한 다음 파일을 변경하고 컴파일 한 다음 객체를 읽으려고하면 이런 일이 발생합니다.

따라서 클래스가 수정되고 다시 컴파일되면 필요한 개체를 파일에 다시 작성하십시오.

추신 : 이것은 해결책이 아닙니다. 해결 방법이었습니다.

참조 URL : https://stackoverflow.com/questions/8335813/java-serialization-java-io-invalidclassexception-local-class-incompatible

반응형