1. 소개
이 예제에서 우리는 자바의 java.io.Externalizable 인터페이스 를 간단히 살펴볼 것 입니다. 이 인터페이스의 주요 목표는 사용자 지정 직렬화 및 역직렬화를 용이하게 하는 것입니다.
계속 진행하기 전에 Java의 직렬화 문서 를 확인 하십시오. 다음 장에서는 이 인터페이스를 사용하여 Java 객체를 직렬화하는 방법에 대해 설명합니다.
그런 다음 java.io.Serializable 인터페이스 와 비교하여 주요 차이점에 대해 논의할 것 입니다.
2. 외부화 가능한 인터페이스
Externalizable 은 java.io.Serializable 마커 인터페이스에서 확장됩니다. Externalizable 인터페이스 를 구현하는 모든 클래스 는 writeExternal() , readExternal() 메서드 를 재정의해야 합니다 . 그렇게 하면 JVM의 기본 직렬화 동작을 변경할 수 있습니다.
2.1. 직렬화
이 간단한 예를 살펴보겠습니다.
public class Country implements Externalizable {
private static final long serialVersionUID = 1L;
private String name;
private int code;
// getters, setters
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(name);
out.writeInt(code);
}
@Override
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
this.name = in.readUTF();
this.code = in.readInt();
}
}
여기 에서 Externalizable 인터페이스를 구현하고 위에서 언급한 두 가지 방법 을 구현하는 Country 클래스를 정의했습니다.
writeExternal() 메서드 에서 객체의 속성을 ObjectOutput 스트림에 추가합니다. 여기에는 String 에 대한 writeUTF() 및 int 값에 대한 writeInt() 와 같은 표준 메서드가 있습니다.
다음으로, 객체를 역직렬화하기 위해 readUTF(), readInt() 메서드를 사용하여 ObjectInput 스트림 에서 읽어서 작성된 것과 동일한 순서로 속성을 읽습니다.
serialVersionUID 를 수동으로 추가하는 것이 좋습니다 . 이것이 없으면 JVM이 자동으로 추가합니다.
자동으로 생성된 숫자는 컴파일러에 따라 다릅니다. 이것은 가능성이 없는 InvalidClassException 을 일으킬 수 있음을 의미합니다 .
위에서 구현한 동작을 테스트해 보겠습니다.
@Test
public void whenSerializing_thenUseExternalizable()
throws IOException, ClassNotFoundException {
Country c = new Country();
c.setCode(374);
c.setName("Armenia");
FileOutputStream fileOutputStream
= new FileOutputStream(OUTPUT_FILE);
ObjectOutputStream objectOutputStream
= new ObjectOutputStream(fileOutputStream);
c.writeExternal(objectOutputStream);
objectOutputStream.flush();
objectOutputStream.close();
fileOutputStream.close();
FileInputStream fileInputStream
= new FileInputStream(OUTPUT_FILE);
ObjectInputStream objectInputStream
= new ObjectInputStream(fileInputStream);
Country c2 = new Country();
c2.readExternal(objectInputStream);
objectInputStream.close();
fileInputStream.close();
assertTrue(c2.getCode() == c.getCode());
assertTrue(c2.getName().equals(c.getName()));
}
이 예에서는 먼저 Country 개체를 만들고 파일에 씁니다. 그런 다음 파일에서 개체를 역직렬화하고 값이 올바른지 확인합니다.
인쇄된 c2 객체 의 출력 :
Country{name='Armenia', code=374}
이것은 객체가 성공적으로 역직렬화되었음을 보여줍니다.
2.2. 계승
클래스가 Serializable 인터페이스 에서 상속할 때 JVM은 하위 클래스의 모든 필드도 자동으로 수집하여 직렬화 가능하게 만듭니다.
이것을 Externalizable 에도 적용할 수 있음을 명심하십시오 . 상속 계층의 모든 하위 클래스에 대해 읽기/쓰기 메서드를 구현하기만 하면 됩니다.
아래 에서 이전 섹션 의 Country 클래스 를 확장 한 Region 클래스 를 살펴보겠습니다 .
public class Region extends Country implements Externalizable {
private static final long serialVersionUID = 1L;
private String climate;
private Double population;
// getters, setters
@Override
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
out.writeUTF(climate);
}
@Override
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
super.readExternal(in);
this.climate = in.readUTF();
}
}
여기에 두 개의 추가 속성을 추가하고 첫 번째 속성을 직렬화했습니다.
상위 클래스 필드도 저장/복원하기 위해 직렬 변환기 메서드 내 에서 super.writeExternal(out), super.readExternal(in) 을 호출 했습니다 .
다음 데이터로 단위 테스트를 실행해 보겠습니다.
Region r = new Region();
r.setCode(374);
r.setName("Armenia");
r.setClimate("Mediterranean");
r.setPopulation(120.000);
다음은 역직렬화된 개체입니다.
Region{
country='Country{
name='Armenia',
code=374}'
climate='Mediterranean',
population=null
}
Region 클래스에서 인구 필드를 직렬화하지 않았기 때문에 해당 속성의 값은 null입니다 .
3. 외부화 가능 vs 직렬화 가능
두 인터페이스의 주요 차이점을 살펴보겠습니다.
- 직렬화 책임
여기서 중요한 차이점은 직렬화 프로세스를 처리하는 방법입니다. 클래스가 java.io.Serializable 인터페이스를 구현할 때 JVM은 클래스 인스턴스 직렬화에 대한 전적인 책임을 집니다. Externalizable 의 경우 전체 직렬화 및 역직렬화 프로세스를 처리해야 하는 것은 프로그래머입니다.
- 사용 사례
전체 객체를 직렬화해야 하는 경우 직렬화 가능 인터페이스가 더 적합합니다. 반면 에 사용자 정의 직렬화의 경우 Externalizable 을 사용하여 프로세스를 제어할 수 있습니다 .
- 성능
java.io.Serializable 인터페이스 는 상대적으로 느린 성능을 유발하는 리플렉션 및 메타데이터를 사용합니다. 이에 비해 Externalizable 인터페이스는 직렬화 프로세스를 완전히 제어할 수 있습니다.
- 읽기 순서
Externalizable 을 사용하는 동안 작성된 순서대로 모든 필드 상태를 읽어야 합니다. 그렇지 않으면 예외가 발생합니다.
예를 들어 Country 클래스 에서 코드 및 이름 속성 의 읽기 순서를 변경하면 java.io.EOFException 이 발생합니다.
한편 Serializable 인터페이스에는 그러한 요구 사항이 없습니다.
- 사용자 정의 직렬화
일시적인 키워드 로 필드를 표시하여 직렬화 가능 인터페이스로 사용자 정의 직렬화를 달성할 수 있습니다 . JVM은 특정 필드를 직렬화하지 않지만 기본값을 사용하여 파일 스토리지에 필드를 추가합니다 . 그렇기 때문에 사용자 정의 직렬화의 경우 Externalizable 을 사용하는 것이 좋습니다.
4. 결론
Externalizable 인터페이스 에 대한 이 짧은 사용방법(예제) 에서는 주요 기능, 장점 및 간단한 사용의 예를 설명했습니다. 또한 Serializable 인터페이스와 비교했습니다.
평소와 같이 예제의 전체 소스 코드는 GitHub에서 사용할 수 있습니다 .