이 기사에서는 Java의 객체 직렬화 및 사막화에 대해 설명합니다. 참조를 위해 모든 사람을 위해 공유하십시오. 세부 사항은 다음과 같습니다.
1. 소개
객체 직렬화는 객체를 바이트 시퀀스로 변환하는 과정을 말하는 반면, 사막화는 일련의 바이트를 기반으로 객체를 복원하는 과정입니다.
직렬화는 일반적으로 다음 시나리오에서 사용됩니다.
1. 객체를 영구적으로 저장하고 객체의 바이트 시퀀스를 로컬 파일에 저장하십시오.
2. 네트워크의 객체를 직렬화하여 객체를 통과합니다.
3. 직렬화를 통해 프로세스 간의 객체를 통과합니다.
객체가 속한 클래스는 직렬화되도록 직렬화 가능 또는 외부화 가능한 인터페이스를 구현해야합니다. 직렬화 가능한 인터페이스를 구현하는 클래스의 경우, 직렬화 및 사형화는 기본화 가능한 인터페이스를 상속받으며 외부화 가능한 인터페이스 클래스의 확장을 완전히 제어합니다.
java.io.objectOutputStream은 객체 출력 스트림을 나타내며, 그 메소드 writeObject (Object OBJ)는 객체의 직렬화를 실현하고 얻은 바이트 시퀀스를 대상 출력 스트림에 쓸 수 있습니다.
java.io.objectinputStream은 객체 입력 스트림을 나타내며, readoBject () 메소드는 소스 입력 스트림에서 일련의 바이트 시퀀스를 읽고 객체로 삼아 반환 할 수 있습니다.
2. 직렬화하는 몇 가지 방법
고객의 직렬화 방법에 따라 고객 클래스가 정의되었다고 가정하면 다음과 같은 직렬화 방법이있을 수 있습니다.
1. 직렬화 가능, 정의되지 않은 readObject 및 WriteObject 메소드를 구현하십시오
ObjectOutputStream은 JDK를 사용하여 기본적으로 고객 객체의 비 투자 인스턴스 변수를 직렬화합니다.
ObjectInputStream JDK 기본 메소드를 사용하여 고객 객체의 비 투자 인스턴스 변수를 사로화합니다.
2. 직렬화 가능한 구현 및 readObject 및 WriteObject 메소드를 정의하십시오
ObjectOutputStream은 고객 객체의 비 투자 인스턴스 변수를 직렬화하기 위해 고객 클래스의 writeObject (ObjectOutputStream out) 메소드를 호출합니다.
ObjectInputStream은 고객 클래스의 readObject (ObjectInputStream in) 메소드를 호출하여 고객 객체의 비 초래 인스턴스 변수를 실질화시킵니다.
3. 외부화 가능성을 구현하고 ReadExternal 및 WriteExternal 방법을 정의하십시오
ObjectOutputStream은 고객 객체의 비 투자 인스턴스 변수를 직렬화하기 위해 고객 클래스의 WriteExternal 메소드를 호출합니다.
ObjectInputStream 먼저 고객 클래스의 매개 변수가없는 생성자를 통해 객체를 인스턴스화 한 다음 ReadExternal 메소드를 사용하여 고객 객체의 비 투자 인스턴스 변수를 사로화합니다.
3. 직렬화 가능한 인터페이스
이 클래스는 java.io.serializable 인터페이스를 구현하여 직렬화 기능을 가능하게합니다. 이 인터페이스를 구현하지 않는 클래스는 해당 주 중 어느 곳에서나 직렬화하거나 사형화 할 수 없습니다. 직렬화 가능한 클래스의 모든 하위 유형은 그 자체로 직렬화 가능합니다. 직렬화 인터페이스에는 방법이나 필드가 없으며 직렬화 가능한 의미를 식별하는 데만 사용됩니다.
사막화 과정에서 비 시리얼 클래스의 분야는 클래스의 공통 또는 보호 된 매개 변수없는 생성자를 사용하여 초기화됩니다. 직렬화 가능한 서브 클래스는 매개 변수가없는 생성자에 액세스 할 수 있어야합니다. 직렬화 가능한 서브 클래스 일 수있는 필드는 스트림에서 복원됩니다.
클래스 뷰를 가로 지르면 직렬화 가능한 인터페이스를 지원하지 않는 객체를 만날 수 있습니다. 이 경우, 수명이없는 예고가 발생하고 일련의 외부화가없는 클래스가 확인됩니다.
1. 정확한 서명
직렬화 및 사막화 중 특별 처리가 필요한 클래스는 다음과 같은 정확한 서명을 사용하여 특별한 방법을 구현해야합니다.
private void writeObject (java.io.objectoutputStream)는 ioException을 던졌습니다
private void readObject (java.io.objectinputstream in)는 ioexception, classNotFoundException;
private void readObjectNodata ()는 ObjectStreamException을 던졌습니다.
writeObject 메소드는 해당 readObject 메소드가 복원 할 수 있도록 특정 클래스의 객체의 상태를 작성해야합니다. out.defaultWriteObject를 호출하여 객체의 필드를 저장하기위한 기본 메커니즘을 호출 할 수 있습니다. 이 방법 자체는 슈퍼 클래스 또는 서브 클래스에 속하는 상태를 포함 할 필요가 없습니다. State는 WriteObject 메소드를 사용하여 개별 필드를 ObjectOutputStream에 작성하거나 기본 데이터 유형에 대해 DataOutput에서 지원하는 메소드를 사용하여 저장할 수 있습니다.
readObject 메소드는 스트림에서 클래스 필드를 읽고 복원 할 책임이 있습니다. DefaultReadoBject를 호출하여 기본 메커니즘을 호출하여 객체의 비 정적 및 비 번역 필드를 복원 할 수 있습니다. DefaultReadoBject 메소드는 스트림에서 정보를 사용하여 현재 객체의 해당 지정된 필드를 통해 저장된 스트림에 객체의 필드를 할당합니다. 이것은 계급 진화 후 새로운 분야를 추가 해야하는 상황을 다루는 데 사용됩니다. 이 방법 자체는 슈퍼 클래스 또는 서브 클래스에 속하는 상태를 포함 할 필요가 없습니다. State는 WriteObject 메소드를 사용하여 개별 필드를 ObjectOutputStream에 작성하거나 기본 데이터 유형에 대해 DataOutput에서 지원하는 메소드를 사용하여 저장할 수 있습니다.
직렬화 스트림이 주어진 클래스를 사형화 할 슈퍼 클래스로 나열하지 않는 경우, readobjectnodata 메소드는 특정 클래스의 객체 상태를 초기화 할 책임이 있습니다. 이는 수신자가 사용하는 사형화 된 인스턴스 클래스가 발신자와 다르고 수신기 버전으로 확장 된 클래스가 발신자 버전에 의해 확장되지 않은 경우에 발생합니다. 또한 직렬화 스트림이 변조되었을 때 발생합니다. 따라서 readobjectnodata 방법은 소스 스트림이 "적대적"인지 불완전한 지에 관계없이 변형 된 물체를 올바르게 초기화 할 수 있습니다.
스트림에 개체를 작성할 때 사용할 대체 객체의 직렬화 가능한 클래스를 지정해야하며 정확한 서명 으로이 특수 메소드를 구현해야합니다.
Ade-Access-Modifier 객체 writeereplace ()는 ObjectStreamException을 던졌습니다.
이 방법은이 메소드가 존재하는 경우 직렬화 된 객체의 클래스에 정의 된 메소드에 의해 액세스 할 수있는 경우 직렬화에 의해 호출됩니다. 따라서이 방법은 비공개, 보호 및 패키지-민간 액세스를 가질 수 있습니다. 이 방법에 대한 서브 클래스 액세스는 Java 액세스 규칙을 따릅니다.
스트림에서 클래스 인스턴스를 읽을 때 대체 클래스 가이 특수 메소드를 구현하기 위해 사용해야하는 정확한 서명을 지정해야합니다.
Ade-Access-Modifier Object ReadResolve ()는 ObjectStreamException을 던졌습니다.
이 readResolve 방법은 WriteRePlace와 동일한 호출 규칙 및 액세스 규칙을 따릅니다.
클래스가 readresolve 메소드를 정의하면, readresolve 방법이 사막화 끝에 호출되고,이 방법에 의해 반환 된 객체는 사막화의 최종 결과입니다.
2. 서식성
Serialization 런타임은 SerialversionUid라는 버전 번호를 사용하여 각 직렬화 가능한 클래스와 연결합니다. 이는 사제로 사용하여 직렬화 클래스에로드 된 직렬화 된 객체의 발신자 및 수신자를 확인합니다. 수신기가 해당 발신자의 버전 번호와 다른 객체 클래스의 SerialversionUid를로드하면, 사로화하면 InvalidClassexception이 발생합니다. 직렬화 가능한 클래스는 "SerialversionUid"라는 필드를 선언하여 자체 SerialversionUid를 명시 적으로 선언 할 수 있습니다 (해당 필드는 정적, 최종 긴 필드 여야합니다).
임의의 액세스-수정기 정적 최종 최종 긴 SerialversionUID = 42L;
직렬화 가능한 클래스가 SerialversionUid를 명시 적으로 선언하지 않으면 Serialization 런타임은 "Java (TM) 객체 직렬화 사양"에 설명 된대로 클래스의 다양한 측면을 기반으로 클래스의 기본 직렬 버전 값을 계산합니다. 그러나 기본 직렬 버전의 계산은 클래스의 세부 사항에 매우 민감하고 컴파일러 구현에 따라 크게 다를 수 있기 때문에 모든 직렬화 가능한 클래스는 직렬 버전 값 값을 명시 적으로 선언하는 것이 좋습니다. 결과가 발생할 수 있습니다. 따라서, 다른 Java 컴파일러에서 Serialversionuid 값 사이의 일관성을 보장하기 위해 Serialized 클래스는 명시 적 SerialversionUid 값을 선언해야합니다. 또한 개인 수정자를 사용하여 가능한 경우 선언 SerialversionUid를 표시하는 것이 좋습니다. 그러한 선언은 클래스를 직접 선언하는 데만 사용되므로 상속 회원으로서의 SerialversionUid 필드는 사용되지 않습니다. 배열 클래스는 명시 적 SerialversionUid를 선언 할 수 없으므로 항상 기본 계산 값을 가지지 만 배열 클래스는 SerialversionUid 값 요구 사항과 일치하지 않습니다.
3. 외향적 인 인터페이스
외부화 가능한 인터페이스를 구현하는 클래스의 직렬화는 다음과 같습니다.
직렬화 중에 클래스의 방법을 writexternal로 호출하고 ReadExternal 방법을 제한하십시오.
사제화를 수행 할 때, 클래스의 매개 변수가없는 생성자를 먼저 불러옵니다. 따라서 직렬화를 구현하는 클래스의 경우, 공개 매개 변수가없는 생성자가 제공되어야합니다.
넷째, 요약
클래스가 직렬화 가능한 인터페이스를 구현하는 한 기본 직렬화 방법이 채택되면 인스턴스를 직렬화 할 수 있습니다. 일반적으로 상속을 위해 특별히 설계된 클래스는 직렬화 가능한 인터페이스를 구현하지 않으려 고 노력해야합니다. 일단 상위 클래스가 직렬화 가능한 인터페이스를 구현하면 모든 서브 클래스가 직렬화 가능하기 때문입니다.
기본 직렬화 방법의 단점 :
1. 객체 공개에 적합하지 않은 민감한 데이터를 직접 직접화하는 것은 안전하지 않습니다.
2. 객체의 멤버 변수가 올바른 제약 조건을 충족하는지 여부를 확인하지 않으며 데이터를 조작하고 비정상적인 작동을 유발할 수 있습니다.
3. 객체 그래프의 재귀 횡단이 필요한 경우 많은 자원을 소비하고 Java 가상 머신의 스택 오버 플로우를 유발합니다.
4. 클래스의 내부 구현으로 클래스의 인터페이스를 제한하여 클래스의 업그레이드 및 유지 보수를 제한합니다.
직렬화 가능한 인터페이스의 개인 유형 writeObject () 및 readObject ()를 구현하거나 외부화 가능한 인터페이스를 구현하고 writeExternal () 및 readExternal () 메소드를 구현하고 공개 유형 매개 변수가없는 생성자를 제공하는 두 가지 방법을 제어하는 두 가지 방법을 제공합니다. 기본 직렬화 방법의 단점을 효과적으로 피할 수 있습니다.
이 기사는 모든 사람의 Java 프로그램 설계에 도움이되기를 바랍니다.