>  기사  >  Java  >  Java의 객체 직렬화 및 역직렬화에 대한 자세한 설명

Java의 객체 직렬화 및 역직렬화에 대한 자세한 설명

高洛峰
高洛峰원래의
2017-01-18 11:22:161368검색

이 기사의 예에서는 Java의 객체 직렬화 및 역직렬화를 설명합니다. 참고할 수 있도록 모든 사람과 공유하세요.

1. 소개

객체 직렬화(Serialized)는 객체를 바이트 시퀀스로 변환하는 과정을 말하며, 역직렬화는 객체를 바이트 시퀀스로 복원하는 과정을 말합니다. 바이트 시퀀스.

직렬화는 일반적으로 다음 시나리오에서 사용됩니다.

1. 개체를 영구적으로 저장하고 개체의 바이트 시퀀스를 로컬 파일에 저장합니다.
2. 네트워크 객체 전달
3. 직렬화를 통해 프로세스 간에 객체를 전달합니다.

객체가 속한 클래스는 직렬화를 위해 직렬화 가능 또는 외부화 가능 인터페이스를 구현해야 합니다. Serialize 인터페이스를 구현하는 클래스의 경우 직렬화 및 역직렬화를 위해 기본 직렬화 방법이 사용됩니다. 역직렬화 동작.

Java.io.ObjectOutputStream은 객체 출력 스트림을 나타냅니다. 해당 메서드 writeObject(Object obj)는 객체의 직렬화를 실현하고 획득한 바이트 시퀀스를 대상 출력 스트림에 쓸 수 있습니다.

Java.io.ObjectInputStream은 객체 입력 스트림을 나타냅니다. 해당 readObject() 메서드는 소스 입력 스트림에서 바이트 시퀀스를 읽고 이를 객체로 역직렬화한 후 반환할 수 있습니다.

2. 여러 가지 직렬화 방법

Customer 클래스가 정의되어 있다고 가정합니다. 고객이 직렬화를 구현하는 방식에 따라 다음과 같은 직렬화 방법이 있을 수 있습니다.

1. 직렬화 가능하고 정의되지 않은 readObject 및 writeObject 메소드 구현

ObjectOutputStream은 JDK 기본 메소드를 사용하여 Customer 객체의 비일시적 인스턴스 변수를 직렬화합니다.
ObjectInputStream은 JDK 기본 메소드를 사용하여 Customer 객체의 비일시적 인스턴스 변수를 직렬화합니다. Customer 객체 인스턴스 변수는 역직렬화됩니다.

2. Serializing을 구현하고 readObject 및 writeObject 메서드를 정의합니다.

ObjectOutputStream은 Customer 클래스의 writeObject(ObjectOutputStream out) 메서드를 호출하여 Customer 개체의 비일시적 인스턴스 변수를 직렬화합니다. 🎜 >ObjectInputStream은 Customer 클래스의 readObject(ObjectInputStream in) 메서드를 호출하여 Customer 개체의 비일시적 인스턴스 변수를 역직렬화합니다.

3. 외부화 가능 구현 및 readExternal 및 writeExternal 메소드 정의

ObjectOutputStream은 Customer 클래스의 writeExternal 메소드를 호출하여 Customer 객체의 비일시적 인스턴스 변수를 직렬화합니다.

ObjectInputStream 매개 변수가 없는 생성자는 Customer 클래스의 writeExternal 메서드를 전달한 다음 readExternal 메서드를 사용하여 Customer 개체의 비일시적 인스턴스 변수를 역직렬화합니다.

3. 직렬화 가능 인터페이스

클래스는 직렬화 기능을 활성화하기 위해 java.io.Serialized 인터페이스를 구현합니다. 이 인터페이스를 구현하지 않는 클래스는 해당 상태를 직렬화하거나 역직렬화할 수 없습니다. 직렬화 가능 클래스의 모든 하위 유형은 그 자체로 직렬화 가능합니다. 직렬화 인터페이스에는 메서드나 필드가 없으며 직렬화 가능한 의미 체계를 식별하는 데에만 사용됩니다.

역직렬화 프로세스 중에 직렬화할 수 없는 클래스의 필드는 클래스의 공개 또는 보호된 매개변수 없는 생성자 메서드를 사용하여 초기화됩니다. 직렬화 가능 서브클래스는 매개변수 없는 생성자에 액세스할 수 있어야 합니다. 직렬화 가능한 서브클래스의 필드는 이 스트림에서 복원됩니다.

클래스 뷰를 탐색할 때 직렬화 가능 인터페이스를 지원하지 않는 객체를 만날 수 있습니다. 이 경우 NotSerializedException이 발생하고 직렬화할 수 없는 개체의 클래스가 식별됩니다.

1. 정확한 시그니처

직렬화 및 역직렬화 중에 특별한 처리가 필요한 클래스는 특수 메서드를 구현하기 위해 다음과 같은 정확한 시그니처를 사용해야 합니다.

private void writeObject( java.io. ObjectOutputStream out)이 IOException을 발생시킵니다

private void readObject(java.io.ObjectInputStream in)가 IOException을 발생시키고 ClassNotFoundException;
private void readObjectNoData()가 ObjectStreamException을 발생시킵니다.

writeObject 메소드가 쓰기를 담당합니다. 해당 readObject 메소드가 복원할 수 있도록 특정 클래스의 객체입니다. 객체 필드를 저장하는 기본 메커니즘은 out.defaultWriteObject를 호출하여 호출할 수 있습니다. 메서드 자체에는 슈퍼클래스나 서브클래스에 속하는 상태가 포함될 필요가 없습니다. writeObject 메소드를 사용하거나 기본 데이터 유형에 대해 DataOutput에서 지원하는 메소드를 사용하여 ObjectOutputStream에 개별 필드를 기록함으로써 상태를 저장할 수 있습니다.

readObject 메소드는 스트림에서 클래스 필드를 읽고 복원하는 일을 담당합니다. in.defaultReadObject를 호출하여 객체의 비정적 및 비일시적 필드를 복원하기 위한 기본 메커니즘을 호출할 수 있습니다. defaultReadObject 메소드는 스트림의 정보를 사용하여 현재 객체의 해당 지정된 필드가 보유하는 스트림의 객체 필드를 할당합니다. 이는 클래스가 발전한 후 새 필드를 추가해야 하는 상황을 처리하는 데 사용됩니다. 메서드 자체에는 슈퍼클래스나 서브클래스에 속하는 상태가 포함될 필요가 없습니다. writeObject 메소드를 사용하거나 기본 데이터 유형에 대해 DataOutput에서 지원하는 메소드를 사용하여 ObjectOutputStream에 개별 필드를 기록함으로써 상태를 저장할 수 있습니다.

readObjectNoData 메소드는 직렬화 스트림이 주어진 클래스를 역직렬화할 객체의 슈퍼클래스로 나열하지 않는 경우 특정 클래스의 객체 상태를 초기화하는 역할을 합니다. 이는 수신자가 발신자와 다른 버전의 역직렬화된 인스턴스 클래스를 사용하고 수신자의 버전이 발신자의 버전에 의해 확장되지 않는 클래스를 확장하는 경우에 발생합니다. 이는 직렬화 스트림이 변조된 경우에도 발생합니다. 따라서 readObjectNoData 메서드를 사용하면 소스 스트림이 "적대적"인지 불완전한지 여부에 관계없이 역직렬화된 개체를 올바르게 초기화할 수 있습니다.

스트림에 객체를 쓸 때 사용할 대체 객체의 직렬화 가능 클래스를 지정해야 합니다. 이 특수 메서드는 정확한 서명으로 구현되어야 합니다.

ANY-ACCESS-MODIFIER 객체 writeReplace( )는 ObjectStreamException을 발생시킵니다.
이 writeReplace 메소드는 이 메소드가 존재하고 직렬화되는 객체의 클래스에 정의된 메소드를 통해 액세스할 수 있는 경우 직렬화에 의해 호출됩니다. 따라서 이 메서드는 개인, 보호 및 패키지 개인 액세스를 가질 수 있습니다. 서브클래스에 의한 이 메소드에 대한 액세스는 Java 액세스 규칙을 따릅니다.

스트림에서 클래스의 인스턴스를 읽을 때 대체 클래스가 이 특수 메서드를 구현하는 데 사용해야 하는 정확한 서명을 지정해야 합니다.

ANY-ACCESS-MODIFIER 객체 readResolve()가 ObjectStreamException을 발생시킵니다.
이 readResolve 메소드는 writeReplace와 동일한 호출 규칙 및 액세스 규칙을 따릅니다.
클래스가 readResolve 메서드를 정의하는 경우 deserialization이 끝나면 readResolve 메서드가 호출되며 이 메서드에서 반환되는 객체는 deserialization의 최종 결과입니다.

2.serialVersionUID

직렬화 런타임은 serialVersionUID라는 버전 번호를 사용하여 직렬화 가능한 각 클래스와 연결합니다. 이 클래스는 직렬화 해제 프로세스 중에 시퀀스를 확인하는 데 사용됩니다. 직렬화의 발신자와 수신자가 객체가 객체에 대한 직렬화 호환 클래스를 로드했습니다. 수신자가 로드한 객체 클래스의 serialVersionUID가 발신자 클래스의 해당 버전 번호와 다른 경우 역직렬화로 인해 InvalidClassException이 발생합니다. 직렬화 가능 클래스는 "serialVersionUID"라는 필드(정적 최종 긴 필드여야 함)를 선언하여 자체 serialVersionUID를 명시적으로 선언할 수 있습니다.
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
직렬화 가능한 클래스인 경우 클래스가 serialVersionUID를 명시적으로 선언하지 않으면 직렬화 런타임은 "Java(TM) 객체 직렬화 사양"에 명시된 대로 클래스의 측면을 기반으로 클래스의 기본 serialVersionUID 값을 계산합니다. 그러나 모든 직렬화 가능 클래스는 serialVersionUID 값을 명시적으로 선언하는 것이 좋습니다. 그 이유는 기본 serialVersionUID 계산이 클래스의 세부 사항에 매우 민감하고 컴파일러 구현에 따라 크게 달라질 수 있기 때문입니다. 예기치 않은 InvalidClassException이 발생합니다. 따라서 다양한 Java 컴파일러 구현에서 serialVersionUID 값의 일관성을 보장하려면 직렬화 클래스에서 명시적인 serialVersionUID 값을 선언해야 합니다. 또한 가능한 경우 private 수정자를 사용하여 serialVersionUID를 명시적으로 선언하는 것이 좋습니다. 그 이유는 이러한 선언은 클래스를 직접 선언하는 데에만 사용해야 하기 때문입니다. serialVersionUID 필드는 상속된 멤버로 사용되지 않습니다. 배열 클래스는 명시적인 serialVersionUID를 선언할 수 없으므로 항상 기본 계산 값을 가지지만 배열 클래스가 serialVersionUID 값과 일치할 필요는 없습니다.

3.외부화 가능 인터페이스

외부화 가능은 Serailized의 확장입니다. 외부화 가능 인터페이스를 구현하는 클래스의 직렬화는 다음과 같은 특징을 갖습니다.
클래스의 writeExternal 메소드는 실행 중에 호출됩니다. readExternal 메소드는 deserialization을 수행할 때 먼저 클래스의 매개변수 없는 생성자를 호출합니다. 따라서 Serialization을 구현하는 클래스는 기본 deserialization과 다릅니다. . 매개변수가 없는 공용 생성자입니다. 그렇지 않으면 역직렬화 중에 예외가 발생합니다.

4. 요약

기본 직렬화 방법을 사용하면 클래스가 직렬화 가능 인터페이스를 구현하는 한 해당 인스턴스를 직렬화할 수 있습니다. 일반적으로 상속을 위해 특별히 설계된 클래스는 직렬화 가능 인터페이스를 구현하지 않아야 합니다. 왜냐하면 상위 클래스가 직렬화 가능 인터페이스를 구현하면 모든 하위 클래스도 직렬화 가능하기 때문입니다.

기본 직렬화 방법의 단점:

1. 대중에게 공개해서는 안 되는 객체의 민감한 데이터를 직접 직렬화하는 것은 안전하지 않습니다. 객체의 멤버 변수가 올바른 제약 조건을 충족하는지 확인하세요. 데이터가 변조되어 비정상적인 작동이 발생할 수 있습니다.

3. 객체 그래프가 매우 복잡하면 재귀적으로 순회해야 합니다. 많은 리소스를 소비하며 이 설정으로 인해 가상 머신의 Java Stack 오버플로가 발생합니다.
4. 클래스의 인터페이스가 클래스의 내부 구현에 의해 제한되어 클래스의 업그레이드 및 유지 관리가 제한됩니다.

직렬화 가능 인터페이스의 비공개 유형 writeObject() 및 readObject()를 구현하거나 외부화 가능 인터페이스를 구현하고 writeExternal() 및 readExternal() 메소드를 구현하고 두 개의 공개 유형 매개변수 없는 생성자를 제공합니다. 직렬화 프로세스를 제어하면 기본 직렬화 방법의 단점을 효과적으로 피할 수 있습니다.

이 글이 모든 분들의 Java 프로그래밍에 도움이 되기를 바랍니다.

Java의 객체 직렬화 및 역직렬화에 대한 자세한 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.