이 기사의 예에서는 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 개체의 비일시적 인스턴스 변수를 역직렬화합니다.
ObjectInputStream 매개 변수가 없는 생성자는 Customer 클래스의 writeExternal 메서드를 전달한 다음 readExternal 메서드를 사용하여 Customer 개체의 비일시적 인스턴스 변수를 역직렬화합니다.
private void readObject(java.io.ObjectInputStream in)가 IOException을 발생시키고 ClassNotFoundException;
private void readObjectNoData()가 ObjectStreamException을 발생시킵니다.
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과 다릅니다. . 매개변수가 없는 공용 생성자입니다. 그렇지 않으면 역직렬화 중에 예외가 발생합니다.
3. 객체 그래프가 매우 복잡하면 재귀적으로 순회해야 합니다. 많은 리소스를 소비하며 이 설정으로 인해 가상 머신의 Java Stack 오버플로가 발생합니다.
4. 클래스의 인터페이스가 클래스의 내부 구현에 의해 제한되어 클래스의 업그레이드 및 유지 관리가 제한됩니다.
직렬화 가능 인터페이스의 비공개 유형 writeObject() 및 readObject()를 구현하거나 외부화 가능 인터페이스를 구현하고 writeExternal() 및 readExternal() 메소드를 구현하고 두 개의 공개 유형 매개변수 없는 생성자를 제공합니다. 직렬화 프로세스를 제어하면 기본 직렬화 방법의 단점을 효과적으로 피할 수 있습니다.
이 글이 모든 분들의 Java 프로그래밍에 도움이 되기를 바랍니다.
Java의 객체 직렬화 및 역직렬화에 대한 자세한 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!