>  기사  >  Java  >  Java 직렬화 및 역직렬화란 무엇입니까? Java 직렬화 및 역직렬화 구현 방법

Java 직렬화 및 역직렬화란 무엇입니까? Java 직렬화 및 역직렬화 구현 방법

不言
不言앞으로
2018-10-13 14:55:573319검색

이 기사에서는 Java 직렬화 및 역직렬화란 무엇인지 설명합니다. Java 직렬화 및 역직렬화 구현 방법은 특정 참고 가치가 있으므로 도움이 필요한 친구가 참고할 수 있기를 바랍니다.

직렬화와 역직렬화는 자바에서 상대적으로 기본적인 지식이지만, 많은 사람들이 몇 문장만 이해하거나 심지어 이해하지 못하는 경우가 많다고 생각합니다. 압도될 수도 있어요! 설명하는 방법, 직렬화란 무엇인지, 역직렬화란 무엇인지, 어떤 시나리오에서 사용될지 등을 모르겠습니다. 면접관은 다음과 같이 말했습니다. 기본 직렬화 및 역직렬화가 어떻게 구현되는지 아십니까? 직렬화 및 역직렬화에 대해 몇 가지 논의해 보겠습니다.

우선, 직렬화와 역직렬화란 무엇인지 개념적으로 명확히 할 필요가 있습니다.

Java는 Java 객체를 바이트 시퀀스로 변환하는 프로세스이고, Java deserialization은 바이트 시퀀스를 Java 객체 프로세스로 복원하는 것을 말합니다.

직렬화: 객체 직렬화의 주요 기능은 객체를 전송하고 저장할 때 객체의 무결성과 전달 가능성을 보장하는 것입니다. 직렬화는 네트워크에서 전송하거나 로컬 파일에 저장하기 위해 객체를 정렬된 바이트 스트림으로 변환하는 것입니다. 직렬화된 바이트 스트림은 Java 객체의 상태 및 관련 설명 정보를 저장합니다. 직렬화 메커니즘의 핵심 기능은 객체 상태를 보존하고 재구성하는 것입니다.

역직렬화: 클라이언트는 파일이나 네트워크에서 직렬화된 객체 바이트 스트림을 얻은 후 바이트 스트림에 저장된 객체 상태 및 설명 정보를 기반으로 역직렬화를 통해 객체를 재구성합니다.

기본적으로 직렬화는 엔터티 객체 상태를 특정 형식의 정렬된 바이트 스트림에 쓰는 것이고, 역직렬화는 정렬된 바이트 스트림에서 객체를 재구성하고 객체 상태를 복원하는 것입니다. 파일 압축 및 압축 해제의 개념과 유사합니다.

직렬화 및 역직렬화가 필요한 이유: ​​

프로세스가 원격으로 통신할 때 텍스트, 그림, 오디오, 비디오 등을 포함한 다양한 유형의 데이터를 서로 보낼 수 있으며 이러한 데이터는 바이너리 시퀀스 형식이 네트워크를 통해 전송됩니다.

그렇다면 두 개의 Java 프로세스가 통신할 때 프로세스 간 객체 전송이 이루어질 수 있을까요? 대답은 '예'입니다. 어떻게 해야 할까요? 이를 위해서는 Java 직렬화 및 역직렬화가 필요합니다.

즉, 발신자는 이 Java 객체를 바이트 시퀀스로 변환한 다음 네트워크에서 전송해야 하며, 수신자는 Java 객체의 바이트 시퀀스에서 복구해야 합니다. .

Java 직렬화와 역직렬화가 왜 필요한지 알게 되면 자연스럽게 Java 직렬화의 장점에 대해 생각하게 됩니다.

먼저 데이터의 지속성이 확보됩니다. 데이터는 직렬화를 통해 하드 디스크에 영구적으로 저장될 수 있습니다(보통 파일에 저장됨).

두 번째는 직렬화를 사용하여 원격 통신, 즉 네트워크에서 개체의 바이트 시퀀스를 전송하는 것입니다.

일반적으로 다음과 같이 요약할 수 있습니다.

(1) 객체를 영구적으로 저장하고 객체의 바이트 시퀀스를 로컬 파일이나 데이터베이스에 저장합니다.
(2) 바이트 스트림 형태로 사용합니다. 직렬화를 통해 객체는 네트워크에서 전송되고 수신됩니다.
(3) 직렬화를 통해 프로세스 간에 객체를 전송합니다.

직렬화 알고리즘은 일반적으로 다음 단계를 수행합니다.

(1) 객체 인스턴스와 관련된 클래스 메타데이터를 출력합니다.
(2) 더 이상 슈퍼클래스가 없을 때까지 클래스의 슈퍼클래스 설명을 반복적으로 출력합니다.
(3) 클래스 메타데이터가 완성되면 최상위 슈퍼클래스부터 객체 인스턴스의 실제 데이터 값이 출력됩니다.
(4) 인스턴스 데이터를 위에서 아래로 반복적으로 출력

자바에서는 직렬화와 역직렬화를 어떻게 구현할까요?

One: JDK 클래스 라이브러리의 직렬화 및 역직렬화 API

(1) java.io.ObjectOutputStream: 객체 출력 스트림을 나타냅니다.

해당 writeObject(Object obj) 메서드는 매개변수화에 의해 지정된 obj 객체를 시퀀스할 수 있습니다.

(2) java.io.ObjectInputStream: 객체 입력 스트림을 나타냅니다.

readObject() 메소드는 소스 입력 스트림에서 바이트 시퀀스를 읽은 다음 이를 객체로 역직렬화합니다.

2: 직렬화 구현을 위한 요구 사항

직렬화 가능 또는 외부화 가능 인터페이스를 구현하는 클래스의 객체만 직렬화할 수 있습니다. 그렇지 않으면 예외가 발생합니다!

3 다음과 같이 직렬화 및 역직렬화할 수 있습니다. ObjectOutputStream은 기본 직렬화 방법을 사용하여 User 개체의 비일시적 인스턴스 변수를 직렬화합니다.

ObjcetInputStream은 기본 역직렬화 방법을 사용하여 User 개체의 비일시적 인스턴스 변수를 역직렬화합니다.

(2) User 클래스가 Serialized 인터페이스만 구현하고 readObject(ObjectInputStream in) 및 writeObject(ObjectOutputSteam out)도 정의하는 경우 직렬화 및 역직렬화를 위해 다음 메서드가 사용됩니다.

ObjectOutputStream调用User对象的writeObject(ObjectOutputStream out)的方法进行序列化。 
ObjectInputStream会调用User对象的readObject(ObjectInputStream in)的方法进行反序列化。

(3)若User类实现了Externalnalizable接口,且User类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。

ObjectOutputStream调用User对象的writeExternal(ObjectOutput out))的方法进行序列化。 
ObjectInputStream会调用User对象的readExternal(ObjectInput in)的方法进行反序列化。

四 :JDK类库中序列化的步骤

1  . 创建一个对象输出流,可以包装一个其它类型的目标输出流,如文件输出流:

ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("D:\\os.out"));

2  . 通过对象输出流的writeObject()方法写对象:

os.writeObject(new User("zhangsan", "123456", "male"));

五  : JDK类库中反序列化的步骤

1  . 创建一个对象输入流,它可以包装一个其它类型输入流,如文件输入流:

ObjectInputStream ois= new ObjectInputStream(new FileInputStream("object.out"));

2  .通过对象输出流的readObject()方法读取对象:

User user = (User) ois.readObject();

为保证正确读取数据,完成反序列化,必须保证向对象输出流写对象的顺序与从对象输入流中读对象的顺序一致。

举个栗子:

public class SerialDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //序列化
        FileOutputStream outputos = new FileOutputStream("object.out");
        ObjectOutputStream oos = new ObjectOutputStream(outputos );
        User user1 = new User("zhangsan", "123456", "male");
        oos.writeObject(user1);
        oos.flush();
        oos.close();
        //反序列化
        FileInputStream inputos= new FileInputStream("object.out");
        ObjectInputStream ois = new ObjectInputStream(inputos);
        User user2 = (User) ois.readObject();
        System.out.println(user2.getUserName()+ " " + 
            user2.getPassword() + " " + user2.getSex());
        //反序列化的输出结果为:zhangsan123456 male
    }
}

public class User implements Serializable {
    private String userName;
    private String password;
    private String sex;
    //全参构造方法、get和set方法
}

  

相关的注意事项:

1、序列化时,只对对象的状态进行保存,而不管对象的方法;

2、当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;

3、当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

4、并非所有的对象都可以序列化,至于为什么不可以,有很多原因了,比如:

安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行RMI传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的;

资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现;

5、声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态,transient代表对象的临时数据。

6、序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。为它赋予明确的值。显式地定义serialVersionUID有两种用途:

在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;

在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

7、Java有很多基础类已经实现了serializable接口,比如String,Vector等。但是也有一些没有实现serializable接口的;

8、如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存!这是能用序列化解决深拷贝的重要原因;

위 내용은 Java 직렬화 및 역직렬화란 무엇입니까? Java 직렬화 및 역직렬화 구현 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 cnblogs.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제