2008-09-03 5 views
7

Java에서 정적 및 일시적인 필드는 직렬화되지 않습니다. 그러나 정적 필드의 초기화로 인해 생성 된 serialVersionUID가 변경된다는 것을 알게되었습니다. 예를 들어 static int MYINT = 3;은 serialVersionUID를 변경합니다. 이 예제에서는 다른 버전의 클래스가 다른 초기 값을 가지므로 의미가 있습니다. 초기화가 serialVersionUID를 변경하는 이유는 무엇입니까? 예를 들어 static String MYSTRING = System.getProperty("foo");도 serialVersionUID를 변경합니다.정적 초기화로 Java 직렬화

구체적으로 말해서, 내 질문은 왜 serialVersionUID가 변경되도록 초기화하는 것입니까? 내가 쳤던 문제는 시스템 속성 값 (getProperty)으로 초기화 된 새로운 정적 필드를 추가했다는 것입니다. 이 변경으로 인해 원격 호출에서 직렬화 예외가 발생했습니다.

답변

5

bug 4365406algorithm for computing serialVersionUID에서 이에 대한 일부 정보를 찾을 수 있습니다. 기본적으로 System.getProperty()으로 static 멤버의 초기화를 변경하면 컴파일러는 System 클래스를 참조하는 클래스에 새로운 static 속성을 도입합니다 (이 경우 클래스에 이전에 System 클래스가 참조되지 않았다고 가정 함).이 속성은 컴파일러에서 도입 된 이후 비공개가 아닌 경우 serialVersionUID 계산에 참여합니다.

도덕 : 항상 당신이 어떤 CPU 사이클과 약간의 두통 :

0

사양을 올바르게 읽으면 자동 serialVersionUID은 일시적인 정적 필드의 값을 변경하면 변경되지 않아야합니다. 사양의 을 살펴보십시오. 당신이 이것에 대해 조금 생각하는 경우

는 - 당신이 다음 다시 같은 개체를 얻을 것으로 예상 클래스를 직렬화 static int MYINT = 3을 가진 개체를 직렬화에 의해 시작, 그 MYINT = 3와 함께입니다. 따라서 정적 초기화를 변경하면 동일한 객체를 다시 가져올 수 없으므로 serialVersionUID이 변경 될 것으로 예상됩니다.

어쨌든을, 모든 직렬화 클래스에서 이것을 유지하고 당신은 serialVersionUID을 제어 할 수 있습니다

private static final long serialVersionUID = 7526472295622776147L; 
0

좀 더 명확하게하는 질문을 업데이트했습니다. 리터럴로 초기화하면 serialVersionUID이 변경되지만 왜 동적 초기화가 변경되지 않는지는 이해합니다. 메소드로 초기화하면 값은 물론 다를 수 있습니다.

serialVersionUID을 명시 적으로 설정하는 것은 안전한 변경이라고 확신하는 경우에만 클래스의 다음 버전에서 유효합니다.

2

자동의 serialVersionUID가 클래스의 멤버를 기반으로 계산을 절약 할 명시 적 serialVersionUID 사용합니다. 이것들은, Sun JDK의 javap 툴을 사용해 클래스 파일로 표시 할 수 있습니다.

질문에 언급 된 경우 추가/제거 된 멤버는 정적 초기화 프로그램입니다. 이것은 클래스 파일에() V로 나타납니다. 메소드의 내용은 javap -c를 사용하여 디스 어셈블 할 수 있습니다. MySTRING에 대한 System.getProperty ("foo") 호출 및 할당을 만들 수 있어야합니다. 그러나 문자열 리터럴 (또는 Java 언어 사양에서 정의한 컴파일 타임 상수)을 사용하여 할당하는 것은 클래스 파일에서 직접 지원되므로 정적 초기화 프로그램이 필요하지 않습니다.

J2SE 1.4 (-source 1.4 -target 1.4) 또는 그 이전의 코드를 대상으로하는 일반적인 경우는 소스 코드 (MyClass.class)의 클래스 리터럴로 표시되는 이전 클래스 인스턴스에 대한 정적 필드입니다. Class 인스턴스는 Class.forName으로 요청시 조회되고 정적 필드에 저장됩니다. 이 정적 필드는 serialVersionUID를 방해합니다. J2SE 5.0에서 ldc opcode의 변형은 클래스 리터럴을 직접 지원하므로 합성 필드가 필요 없습니다. 다시,이 모든 것은 javap -c로 볼 수 있습니다.