Java Serializable
와 Externalizable
Java 의 차이점은 무엇입니까 ?
Java Serializable
와 Externalizable
Java 의 차이점은 무엇입니까 ?
답변:
다른 답변에 추가하기 위해을 구현 java.io.Serializable
하면 클래스 객체에 대한 "자동"직렬화 기능이 제공됩니다. 다른 로직을 구현할 필요가 없으며 작동합니다. Java 런타임은 리플렉션을 사용하여 객체를 마샬링하고 마샬링 해제하는 방법을 알아냅니다.
이전 버전의 Java에서는 리플렉션이 매우 느리기 때문에 클라이언트-서버 RMI 응용 프로그램 등에서 큰 객체 그래프를 직렬화하는 것이 약간의 성능 문제였습니다. 이 상황을 처리 하기 위해 마샬링 및 비 정렬 화 기능 ( 클래스에서 구현 및 메소드 가 필요함)을 수행하기위한 사용자 정의 작성 메커니즘과 java.io.Externalizable
유사 java.io.Serializable
하지만 인터페이스가 제공되었습니다 . 이를 통해 반사 성능 병목 현상을 해결할 수 있습니다.readExternal
writeExternal
최근 버전의 Java (확실히 1.3 이상)에서는 리플렉션 성능이 예전보다 훨씬 우수하므로 문제가 훨씬 적습니다. Externalizable
최신 JVM 을 통해 의미있는 이점을 누리기 위해 열심히 노력한 것 같습니다 .
또한 기본 제공 Java 직렬화 메커니즘이 유일한 것은 아니며 JBoss Serialization과 같은 타사 대체물을 얻을 수 있으며 이는 훨씬 빠르며 기본값을 대체하는 대체물입니다.
큰 단점은 Externalizable
이 논리를 직접 유지해야한다는 것입니다. 클래스에서 필드를 추가, 제거 또는 변경하는 경우이를 처리하기 위해 writeExternal
/ readExternal
메소드를 변경해야 합니다.
요약 Externalizable
하면 Java 1.1 일의 유물입니다. 더 이상 필요가 없습니다.
Externalizable
도움이됩니다 .
Externalizable
빈 공간이나 자리 표시 자 객체로 배열을 출력하고 싶지 않고 상속을 처리 할 수있는 명시 적 인터페이스를 사용하여 배열을 출력하고 싶지 않기 때문에 훨씬 더 적합 하다고 말해야합니다. -class는 호출에 대한 잠금을 쉽게 추가 할 수 있습니다 writeExternal()
. 그렇습니다. Externalizable은 여전히 크거나 복잡한 객체와 관련이 있습니다.
직렬화는 개체를 저장하고 나중에 다시 만드는 기본 기능을 제공합니다. verbose 형식을 사용하여 저장할 오브젝트의 전체 그래프를 정의합니다. 예를 들어 linkedList가 있고 아래와 같이 코드화 한 경우 기본 직렬화는 링크 된 모든 오브젝트를 발견하고 직렬화합니다. 기본 직렬화에서 객체는 생성자 호출없이 저장된 비트로 만 구성됩니다.
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("/Users/Desktop/files/temp.txt"));
oos.writeObject(linkedListHead); //writing head of linked list
oos.close();
그러나 제한된 직렬화를 원하거나 객체의 일부를 직렬화하지 않으려면 Externalizable을 사용하십시오. Externalizable 인터페이스는 Serializable 인터페이스를 확장하고 writeExternal () 및 readExternal ()의 두 가지 메소드를 추가합니다. 직렬화 또는 역 직렬화 중에 자동으로 호출됩니다. Externalizable로 작업하는 동안 기본 생성자는 public이어야하며 그렇지 않으면 코드에서 예외가 발생합니다. 아래 코드를 따르십시오
public class MyExternalizable implements Externalizable
{
private String userName;
private String passWord;
private Integer roll;
public MyExternalizable()
{
}
public MyExternalizable(String userName, String passWord, Integer roll)
{
this.userName = userName;
this.passWord = passWord;
this.roll = roll;
}
@Override
public void writeExternal(ObjectOutput oo) throws IOException
{
oo.writeObject(userName);
oo.writeObject(roll);
}
@Override
public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException
{
userName = (String)oi.readObject();
roll = (Integer)oi.readObject();
}
public String toString()
{
StringBuilder b = new StringBuilder();
b.append("userName: ");
b.append(userName);
b.append(" passWord: ");
b.append(passWord);
b.append(" roll: ");
b.append(roll);
return b.toString();
}
public static void main(String[] args)
{
try
{
MyExternalizable m = new MyExternalizable("nikki", "student001", 20);
System.out.println(m.toString());
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/Desktop/files/temp1.txt"));
oos.writeObject(m);
oos.close();
System.out.println("***********************************************************************");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/Desktop/files/temp1.txt"));
MyExternalizable mm = (MyExternalizable)ois.readObject();
mm.toString();
System.out.println(mm.toString());
}
catch (ClassNotFoundException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
catch(IOException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
기본 생성자를 주석 처리하면 코드에서 예외가 발생합니다.
java.io.InvalidClassException: javaserialization.MyExternalizable;
javaserialization.MyExternalizable; no valid constructor.
우리는 암호가 민감한 정보이기 때문에 writeExternal (ObjectOutput oo) 메소드에서 암호를 직렬화하지 않고 readExternal (ObjectInput oi)에서 동일한 값을 설정하지 않습니다. 이것이 Externalizable에서 제공하는 유연성입니다.
위 코드의 출력은 다음과 같습니다.
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
passWord의 값을 설정하지 않았으므로 null이 될 수 있습니다.
비밀번호 필드를 임시로 선언하여 동일한 결과를 얻을 수도 있습니다.
private transient String passWord;
도움이 되길 바랍니다. 실수 한 경우 사과드립니다. 감사.
간의 주요 차이점 Serializable
및Externalizable
Serializable
방법이없는 마커 인터페이스입니다. Externalizable
인터페이스는 두 가지 방법을 포함 writeExternal()
하고 readExternal()
.Serializable
인터페이스를 구현하는 클래스의 경우 기본 직렬화 프로세스가 시작 됩니다. Externalizable
인터페이스를 구현하는 클래스에 대해 프로그래머 정의 직렬화 프로세스가 시작 됩니다.Externalizable
인터페이스를 완벽하게 제어 할 수 있습니다 . 다른 버전의 객체를 지원할 수 있습니다. 구현하는 경우 클래스 Externalizable
를 직렬화하는 것은 귀하의 책임입니다.super
Serializable
리플렉션을 사용하여 객체를 생성하며 인수 생성자가 필요하지 않습니다. 그러나 Externalizable
인수없는 공개 생성자가 필요합니다.참조 블로그 로 Hitesh Garg
자세한 내용은.
직렬화는 특정 기본 동작을 사용하여 개체를 저장하고 나중에 다시 만듭니다. 참조 및 복잡한 데이터 구조를 처리하는 순서 또는 방법을 지정할 수 있지만 결국 각 기본 데이터 필드에 대한 기본 동작을 사용하게됩니다.
외부화는 데이터 필드에 대한 기본 직렬화 메커니즘을 사용하지 않고 완전히 다른 방식으로 객체를 실제로 저장하고 다시 빌드하려는 드문 경우에 사용됩니다. 예를 들어, 고유 한 인코딩 및 압축 체계가 있다고 가정하십시오.
객체 직렬화는 직렬화 가능 및 외부화 가능 인터페이스를 사용합니다. Java 객체는 직렬화 만 가능합니다. 클래스 또는 그 슈퍼 클래스 중 하나가 java.io.Serializable 인터페이스 또는 해당 서브 인터페이스 java.io.Externalizable을 구현하는 경우 대부분의 자바 클래스는 직렬화 가능하다 .
NotSerializableException
: packageName.ClassName
«직렬화 프로세스에 클래스 객체를 참여 시키려면 클래스가 직렬화 가능 또는 외부화 가능 인터페이스를 구현해야합니다.오브젝트 직렬화는 저장중인 오브젝트의 Java 클래스에 대한 정보가있는 스트림을 생성합니다. 직렬화 가능 오브젝트의 경우, 클래스 구현의 다른 (그러나 호환 가능한) 버전의 구현이 존재하더라도 해당 오브젝트를 복원하기에 충분한 정보가 유지됩니다. 직렬화 가능 인터페이스는 직렬화 가능 프로토콜을 구현하는 클래스를 식별하기 위해 정의됩니다.
package java.io;
public interface Serializable {};
InvalidClassException
«역 직렬화 프로세스에서 로컬 클래스 serialVersionUID 값이 해당 발신자의 클래스와 다른 경우 . 다음과 같이 충돌이 발생합니다
java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
외부화 가능 객체의 경우 객체 클래스의 ID 만 컨테이너에 의해 저장됩니다. 클래스는 내용을 저장하고 복원해야합니다. 외부화 가능 인터페이스는 다음과 같이 정의됩니다.
package java.io;
public interface Externalizable extends Serializable
{
public void writeExternal(ObjectOutput out)
throws IOException;
public void readExternal(ObjectInput in)
throws IOException, java.lang.ClassNotFoundException;
}
OptionalDataException
« 우리가 썼을 때 필드는 반드시 같은 순서와 유형이어야 합니다. 스트림에서 형식이 일치하지 않으면 OptionalDataException이 발생합니다.
@Override public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
직렬화 하기 위해 작성 (노출) 된 클래스의 인스턴스 필드입니다 ObjectOutput
.
예 « 직렬화 가능 구현
class Role {
String role;
}
class User extends Role implements Serializable {
private static final long serialVersionUID = 5081877L;
Integer id;
Address address;
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
}
class Address implements Serializable {
private static final long serialVersionUID = 5081877L;
String country;
}
예 « 는 Externalizable을 구현합니다.
class User extends Role implements Externalizable {
Integer id;
Address address;
// mandatory public no-arg constructor
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
}
예
public class CustomClass_Serialization {
static String serFilename = "D:/serializable_CustomClass.ser";
public static void main(String[] args) throws IOException {
Address add = new Address();
add.country = "IND";
User obj = new User("SE");
obj.id = 7;
obj.address = add;
// Serialization
objects_serialize(obj, serFilename);
objects_deserialize(obj, serFilename);
// Externalization
objects_WriteRead_External(obj, serFilename);
}
public static void objects_serialize( User obj, String serFilename ) throws IOException{
FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
// java.io.NotSerializableException: com.github.objects.Address
objectOut.writeObject( obj );
objectOut.flush();
objectOut.close();
fos.close();
System.out.println("Data Stored in to a file");
}
public static void objects_deserialize( User obj, String serFilename ) throws IOException{
try {
FileInputStream fis = new FileInputStream( new File( serFilename ) );
ObjectInputStream ois = new ObjectInputStream( fis );
Object readObject;
readObject = ois.readObject();
String calssName = readObject.getClass().getName();
System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException
User user = (User) readObject;
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void objects_WriteRead_External( User obj, String serFilename ) throws IOException {
FileOutputStream fos = new FileOutputStream(new File( serFilename ));
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
obj.writeExternal( objectOut );
objectOut.flush();
fos.close();
System.out.println("Data Stored in to a file");
try {
// create a new instance and read the assign the contents from stream.
User user = new User();
FileInputStream fis = new FileInputStream(new File( serFilename ));
ObjectInputStream ois = new ObjectInputStream( fis );
user.readExternal(ois);
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@보다
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
기본 직렬화는 다소 장황하며 직렬화 된 객체의 가능한 가장 넓은 사용 시나리오를 가정하므로 기본 형식 (Serializable)은 직렬화 된 객체의 클래스에 대한 정보로 결과 스트림에 주석을 추가합니다.
외부화는 객체 스트림의 제작자에게 클래스의 최소한의 필수 식별 (예 : 이름)을 넘어서 정확한 클래스 메타 데이터 (있는 경우)를 완벽하게 제어합니다. 이는 객체 스트림의 생산자와 소비자 (스트림에서 객체를 유지하는 소비자)가 일치하고 클래스에 대한 추가 메타 데이터가 목적을 제공하지 않으며 성능을 저하시키는 폐쇄 된 환경과 같은 특정 상황에서 분명히 바람직합니다.
또한 (Uri point out으로) 외부화는 Java 유형에 해당하는 스트림의 데이터 인코딩을 완벽하게 제어합니다. (고려 된) 예제의 경우, 부울 true를 'Y'로, false를 'N'으로 기록 할 수 있습니다. 외부화를 통해 그렇게 할 수 있습니다.
Serializable과 Externalizable 사이에는 많은 차이가 있지만 custom Serializable (overrided writeObject () & readObject ())와 Externalizable의 차이점을 비교할 때 사용자 정의 구현은 Externalizable 경우와 같이 ObjectOutputStream 클래스와 밀접하게 바인딩됩니다. ObjectOutputStream 클래스 일 수도 있고 org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream과 같은 ObjectOutput 구현을 제공합니다.
외부화 가능 인터페이스의 경우
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(key);
out.writeUTF(value);
out.writeObject(emp);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.key = in.readUTF();
this.value = in.readUTF();
this.emp = (Employee) in.readObject();
}
**In case of Serializable interface**
/*
We can comment below two method and use default serialization process as well
Sequence of class attributes in read and write methods MUST BE same.
// below will not work it will not work .
// Exception = java.io.StreamCorruptedException: invalid type code: 00\
private void writeObject(java.io.ObjectOutput stream)
*/
private void writeObject(java.io.ObjectOutputStream Outstream)
throws IOException {
System.out.println("from writeObject()");
/* We can define custom validation or business rules inside read/write methods.
This way our validation methods will be automatically
called by JVM, immediately after default serialization
and deserialization process
happens.
checkTestInfo();
*/
stream.writeUTF(name);
stream.writeInt(age);
stream.writeObject(salary);
stream.writeObject(address);
}
private void readObject(java.io.ObjectInputStream Instream)
throws IOException, ClassNotFoundException {
System.out.println("from readObject()");
name = (String) stream.readUTF();
age = stream.readInt();
salary = (BigDecimal) stream.readObject();
address = (Address) stream.readObject();
// validateTestInfo();
}
더 잘 설명하기 위해 샘플 코드를 추가했습니다. Externalizable의 오브젝트를 체크인 / 체크 아웃하십시오. 이것들은 어떤 구현에도 직접적으로 구속되지 않습니다.
Outstream / Instream은 클래스에 밀접하게 바인딩됩니다. ObjectOutputStream / ObjectInputStream을 확장 할 수는 있지만 사용하기가 약간 어렵습니다.
기본적으로 Serializable
클래스가 직렬화에 안전하고 JVM이 직렬화 방법을 결정 함을 나타내는 마커 인터페이스입니다. Externalizable
이 방법을 포함 readExternal
하고 writeExternal
. Externalizable
구현자가 객체를 직렬화하는 방법을 결정할 수 있습니다 Serializable
.
몇 가지 차이점 :
직렬화의 경우 JVM이 Reflection API의 도움으로 동일하게 구성되므로 Object는 해당 클래스의 기본 생성자가 필요하지 않습니다. arg가없는 외부화 생성자가 필요한 경우, 제어는 프로그래밍에 의해 이루어지고 나중에 직렬화 해제 된 데이터를 setter를 통해 객체에 할당하기 때문입니다.
직렬화에서 사용자가 직렬화 할 특정 특성을 건너 뛰려면 해당 특성을 일시적으로 표시해야하며 그 반대도 외부화에 필요하지 않습니다.
모든 클래스에 대해 이전 버전과의 호환성 지원이 필요한 경우 Externalizable을 사용하는 것이 좋습니다. 직렬화는 defaultObject 지속을 지원하며 객체 구조가 손상된 경우 deserialize하는 동안 문제가 발생합니다.