Serializable 인터페이스에 대한 심층적 이해

Serializalbe의 초기 인상

Serializalbe 는 "Serializable 구현"시 자주 사용되는 J AVA 엔티티 객체 ,이 인터페이스를 구현하는 것으로 일반적으로 알려져 있습니다. 그렇다면 직렬화의 목적은 무엇입니까?

Serializalbe 인터페이스 소스 코드보기

java.ioSerializable { 
}

이것은 상징적 인 인터페이스로 볼 수있는 빈 인터페이스입니다. 주석은이 인터페이스를 구현하지 않는 클래스가 해당 상태의 직렬화 또는 직렬화 해제를 수행하지 않음을 나타냅니다. JVM은이 식별자를 사용하여 직렬화가 필요한지 여부를 식별합니다.

직렬화 가능한 인터페이스 개요

Serializable은 java.io 패키지에 정의 된 시맨틱 레벨 인터페이스이며 Java 클래스의 직렬화 작업을 구현하는 데 사용됩니다. 직렬화 가능 직렬화 인터페이스에는 메소드 나 필드가 없지만 직렬화의 의미를 식별하는 데 사용됩니다. Serializable 인터페이스를 구현하는 클래스는 ObjectOutputStream에 의해 바이트 스트림으로 변환 될 수 있으며 ObjectInputStream을 통해 객체로 구문 분석 될 수도 있습니다. 예를 들어 직렬화 된 객체를 파일에 쓰고 파일에서 다시 읽고 객체로 역 직렬화 할 수 있습니다. 즉, 객체와 해당 데이터를 나타내는 유형 정보와 바이트를 사용하여 메모리에서 객체를 다시 만들 수 있습니다.

그리고 이것은 객체 지향 프로그래밍 언어에서 매우 중요합니다. 어떤 프로그래밍 언어에 관계없이 IO 작업의 기본 부분은 여전히 ​​운영 체제에 의해 수행되고 기본 IO 작업은 모두 바이트 스트림이기 때문에 쓰기 작업에는 프로그래밍 언어 데이터 유형을 바이트 스트림으로 변환하고 읽기 작업에는 바이트 스트림을 프로그래밍 언어 유형의 특정 데이터 유형으로 변환하는 작업이 포함됩니다. Java는 객체 지향 프로그래밍 언어이며 객체는 기본 데이터의 유형 캐리어입니다. 객체 데이터의 읽기 및 쓰기 작업을 완료하려면 JVM이 객체 데이터를 IO로 변환하는 방법을 알려주는 방법이 필요합니다. 바이트 스트림, 바이트 스트림 데이터를 특정 객체로 변환하는 방법 및 Serializable 인터페이스가 이러한 역할을 맡습니다.

실험, 코드보기

【실험 1】

예제를 사용하여 직렬화 된 객체를 파일에 저장 한 다음 파일에서 객체로 역 직렬화 할 수 있습니다. 코드 예제는 다음과 같습니다.

먼저 직렬화 된 개체 사용자를 정의합니다.

사용자 직렬화 가능 { 
    정수 문자열 (정수 idString 이름) { 
        . = id. = 이름}

객체를 파일에 쓰는 첫 번째 테스트 (SpringBoot를 사용하여 액세스 가능한 인터페이스를 설정하고이 인터페이스에 액세스 할 때 파일 쓰기 작업을 실행 함) :

HelloWorldController { 
    (= = RequestMethod.) 
    사용자 (문자열 이름) { 
        사용자 사용자 = 사용자 (이름) { 
            ObjectOutputStream objectOutputStream = ObjectOutputStream (FileOutputStream ()) objectOutputStream.writeObject (user) objectOutputStream.close ()} (IOException e) { 
            e. printStackTrace ()} 


        사용자} 
}

이 인터페이스 (내 로컬 주소)에 접속 한 후 : http://127.0.0.1:8080/hello/say을  , 우리는 사용자 개체와 그 텍스트 TEST.TXT에 전달하는 데이터를 쓸 수 :

image.png

개체 데이터가 디스크 파일에 유지되는지 확인합니다.

[실험 2]

엔티티 클래스에서 직렬화 가능 인터페이스 제거

사용자 { 
    정수 문자열 (정수 idString 이름) { 
        . = id. = 이름}

인터페이스를 다시 실행하면 오류는 다음과 같습니다.

image.pngNotSerializableException 예외가 발생하여 직렬화 할 수없는 예외가 발생합니다. 즉, JVM이 객체를 바이트 스트림으로 자동으로 변환하지 않기 때문에 Serializable 인터페이스를 구현하지 않는 객체는 IO 작업을 통해 지속될 수 없습니다. 프로그램에서 수행 사용자 개체는 지속성 레이어에 직접 저장할 수 없습니다.

【실험 3】

이전에 test.txt 파일에 저장 한 개체 데이터를 Java 개체로 다시 변환합니다. 코드는 다음과 같습니다.


직렬화 및 역 직렬화 정보

직렬화 : Java 객체를 바이트 스트림으로 변환하는 프로세스입니다. 메모리에있는 이러한 개체를 일련의 바이트 (바이트) 설명으로 바꾸는 프로세스입니다.

역 직렬화 : 바이트 스트림을 Java 객체로 변환하는 프로세스입니다.

사용할 장면

1, 이미지 데이터의 상태를 파일 또는 데이터베이스 저장하는 데 필요한 메모리 , 예를 들어 mybatis 지속성 레이어 프레임을 사용할 때 데이터베이스에 개체 데이터 삽입

2. 네트워크 통신을 위해 RPC 프로토콜을 사용하는 경우와 같이 네트워크 통신에서 소켓을 사용하여 네트워크에서 개체를 전송해야하는 경우


보충 자료 (다른 웹 사이트에서 가져옴)

serialVersionUID 정보

JVM의 경우 지속될 클래스에 마크가 있어야합니다.이 마크가 있어야만 JVM이 클래스가 생성 한 객체를 IO 시스템을 통해 바이트 데이터로 변환하여 지속성을 달성 할 수 있으며이 마크는 Serializable 인터페이스입니다. deserialization 과정에서 serialVersionUID를 사용하여 개체를로드 할 클래스를 결정해야합니다. 따라서 Serializable 인터페이스를 구현할 때 일반적으로 serialVersionUID를 가능한 한 명시 적으로 정의해야합니다.

개인 정적 최종 긴 serialVersionUID = 1L;

在反序列化的过程中,如果接收方为对象加载了一个类,如果该对象的serialVersionUID与对应持久化时的类不同,那么反序列化的过程中将会导致InvalidClassException异常。例如,在之前反序列化的例子中,我们故意将User类的serialVersionUID改为2L,如:

private static final long serialVersionUID = 2L;

那么此时,在反序例化时就会导致异常,如下:

java.io.InvalidClassException: cn.wudimanong.serializable.User; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2     at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:687)     at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1880)     at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1746)     at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2037)     at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1568)     at java.io.ObjectInputStream.readObject(ObjectInputStream.java:428)     at cn.wudimanong.serializable.SerializableTest.readObj(SerializableTest.java:31)     at cn.wudimanong.serializable.SerializableTest.main(SerializableTest.java:44)

직렬화에서 serialVersionUID를 명시 적으로 선언하지 않으면 직렬화 런타임은 클래스의 모든 측면에 따라 클래스의 기본 serialVersionUID 값을 계산합니다. 그러나 Java 공식은 직렬화 할 모든 클래스가 명시 적으로 serialVersionUID 필드를 선언 할 것을 강력히 권장합니다. 기본적으로 serialVersionUID를 생성하는 데 JVM에 크게 의존하는 경우 컴파일러의 구현 세부 정보와 결합 될 수 있기 때문입니다. 역 직렬화로 이어질 수 있습니다. 프로세스 중에 예기치 않은 InvalidClassException이 발생했습니다. 따라서 서로 다른 Java 컴파일러에서 구현 된 serialVersionUID 값의 일관성을 보장하기 위해 Serializable 인터페이스를 구현하는 사용자는 serialVersionUID 필드를 명시 적으로 선언해야합니다.

또한 serialVersionUID 필드의 선언은 가능한 한 private 키워드로 수정해야합니다. 이는이 필드의 선언이 선언 된 클래스에만 적용되기 때문입니다.이 필드가 서브 클래스에서 멤버로 상속되는 것은 쓸모가 없습니다. 변수!주의해야 할 특별한 위치가 있습니다., 배열 클래스는 항상 기본 계산 된 값을 가지고 있기 때문에 serialVersionUID를 명시 적으로 선언 할 수 없지만, serialVersionUID 값 일치 요구 사항도 배열 클래스의 역 직렬화 중에 포기됩니다. .



추천

출처blog.51cto.com/13238147/2667199