>  기사  >  Java  >  Java 객체 직렬화 NIO NIO2 세부 소개 및 분석

Java 객체 직렬화 NIO NIO2 세부 소개 및 분석

黄舟
黄舟원래의
2017-03-06 10:44:111306검색

이 글에서는 주로 Java 객체 직렬화 NIO NIO2에 대한 자세한 소개와 분석을 소개합니다. 직렬화 메커니즘을 통해 프로그램 실행과 관계없이 객체가 독립적으로 존재할 수 있습니다.

Java 객체 직렬화 NIO NIO2의 상세 소개 및 분석 NIO2

요약:

객체 직렬화

객체 직렬화 메커니즘을 사용하면 메모리의 Java 객체를 플랫폼 독립적인 바이너리 스트림으로 변환할 수 있으며, 이를 디스크에 저장하거나 네트워크를 통해 전송할 수 있습니다. 다른 프로그램이 이 바이너리 스트림을 얻은 후 이를 원래 Java 객체로 복원할 수 있습니다. 직렬화 메커니즘을 사용하면 프로그램 실행과 관계없이 객체가 독립적으로 존재할 수 있습니다.

직렬화의 의미와 의미

직렬화

직렬화 메커니즘을 통해 다음을 허용할 수 있습니다. 프로그램 실행과 독립적으로 존재하는 객체

직렬화(Serialize)는 Java 객체를 IO 스트림에 쓰는 것을 의미합니다. 이에 따라 객체의 역직렬화(Deserialize)는 IO 스트림에서 객체를 역직렬화하는 것을 의미합니다. . 스트림에서 Java 객체 복원

객체가 직렬화 메커니즘을 지원하도록 해야 하는 경우 클래스를 직렬화하려면 다음 두 인터페이스 중 하나를 구현해야 합니다. :

  • 직렬화 가능: Mark 인터페이스. 이 인터페이스를 구현하면 메소드를 구현할 필요가 없으며 단지 이 클래스의 인스턴스가 직렬화 가능함을 나타냅니다.

  • 외부화 가능

네트워크를 통해 전송되는 모든 객체는 직렬화 가능해야 합니다. 그렇지 않으면 디스크에 저장해야 하는 모든 객체가 예외가 발생합니다. 클래스는 각 JavaBean 클래스에서 직렬화 가능해야 합니다.

직렬화를 구현하기 위해 객체 스트림을 사용하는 프로그램

직렬화를 구현하기 위해 직렬화를 구현하는 클래스, 프로그램은 다음 두 가지를 통해 객체를 직렬화할 수 있습니다. 단계:

1. ObjectOutputStream을 생성합니다. 이 출력 스트림은 처리 스트림이므로 다른 노드 스트림을 기반으로 구축되어야 합니다.

// 创建个ObjectOutputStream输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));

2. ObjectOutputStream 개체의 writeObject 메서드를 호출하여 직렬화 가능 개체를 출력합니다.

// 将一个Person对象输出到输出流中
oos.writeObject(per);

NbaPlayer 클래스를 정의하고, 개체를 식별하는 직렬화 가능 인터페이스를 구현합니다. 이 클래스를 직렬화 가능

public class NbaPlayer implements java.io.Serializable
{
  private String name;
  private int number;
  // 注意此处没有提供无参数的构造器!
  public NbaPlayer(String name, int number)
  {
    System.out.println("有参数的构造器");
    this.name = name;
    this.number = number;
  }

  // name的setter和getter方法
  public void setName(String name)
  {
    this.name = name;
  }
  public String getName()
  {
    return this.name;
  }

  // number的setter和getter方法
  public void setNumber(int number)
  {
    this.number = number;
  }
  public int getNumber()
  {
    return this.number;
  }
}

ObjectOutputStream을 사용하여 디스크 파일에 NbaPlayer 개체 쓰기

import java.io.*;

public class WriteObject
{
  public static void main(String[] args)
  {
    try(
      // 创建一个ObjectOutputStream输出流
      ObjectOutputStream oos = new ObjectOutputStream(
        new FileOutputStream("object.txt")))
    {
      NbaPlayer player = new NbaPlayer("维斯布鲁克", 0);
      // 将player对象写入输出流
      oos.writeObject(player);
    }
    catch (IOException ex)
    {
      ex.printStackTrace();
    }
  }
}

역직렬화

바이너리 스트림에서 Java 객체를 복원하려면 프로그램에서 객체를 직렬화하기 위해 다음 두 단계를 전달할 수 있습니다.

1. ObjectInputStream 입력 스트림을 생성합니다. 이 입력 스트림은 처리 스트림이므로 다른 노드 스트림을 기반으로 구축되어야 합니다

// 创建个ObjectInputStream输出流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));

2. 스트림의 객체를 읽기 위한 ObjectInputStream 객체의 readObject() 메소드. 이 메소드는 실제 유형인

// 从输入流中读取一个Java对象,并将其强制类型转换为Person类
Person p = (Person)ois.readObject();

object.txt 파일에서 NbaPlayer 객체를 읽는 단계

import java.io.*;
public class ReadObject
{
  public static void main(String[] args)
  {
    try(
      // 创建一个ObjectInputStream输入流
      ObjectInputStream ois = new ObjectInputStream(
        new FileInputStream("object.txt")))
    {
      // 从输入流中读取一个Java对象,并将其强制类型转换为NbaPlayer类
      NbaPlayer player = (NbaPlayer)ois.readObject();
      System.out.println("名字为:" + player.getName()
        + "\n号码为:" + player.getNumber());
    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
  }
}

Deserialize read 얻는 것은 Java 객체의 데이터일 뿐, Java 객체의 데이터는 아닙니다. 따라서 역직렬화를 사용하여 Java 객체를 복원하는 경우 Java 객체가 속한 클래스 파일을 제공해야 합니다. 그렇지 않으면 역직렬화 메커니즘이 생성자를 통해 Java를 초기화할 필요가 없습니다. >

직렬화 메커니즘을 사용하여 여러 개의 Java 객체를 파일에 쓰는 경우 역직렬화 메커니즘을 사용하여 복원된 객체를 실제로 작성된 순서대로 읽어야 합니다. 직렬화 가능 클래스에 여러 상위 클래스(직접 상위 클래스 및 간접 상위 클래스 포함)가 있는 경우 이러한 상위 클래스에는 인수가 없는 생성자가 있거나 직렬화도 가능합니다. 그렇지 않으면 역직렬화에서 InvalidClassException이 발생합니다. 상위 클래스가 직렬화 가능하지 않고 매개변수 없는 생성자만 있는 경우 상위 클래스에서 정의한 Field 값은 바이너리 스트림으로 직렬화되지 않습니다.

객체 참조 직렬화

클래스의 필드 유형이 기본 유형이나 문자열 유형이 아니라 다른 참조 유형인 경우 이 참조 유형은 직렬화 가능해야 합니다. 그렇지 않으면 이 유형의 필드를 사용하는 클래스는 직렬화될 수 없습니다.

public class AllStar implements java.io.Serializable
{
  private String name;
  private NbaPlayer player;
  public AllStar(String name, NbaPlayer player)
  {
    this.name = name;
    this.player = player;
  }
  // 此处省略了name和player的setter和getter方法

  // name的setter和getter方法
  public String getName()
  {
    return this.name;
  }

  public void setName(String name)
  {
    this.name = name;
  }

  // player的setter和getter方法
  public NbaPlayer getPlayer() 
  {
    return player;
  }

  public void setPlayer(NbaPlayer player) 
  {
    this.player = player;
  }
}

Java 특수 직렬화 알고리즘

    모두 디스크에 저장됩니다. 의 객체에는 일련번호가 있습니다
  • 프로그램이 개체를 직렬화하려고 하면 프로그램은 먼저 개체가 직렬화되었는지 여부를 확인하고 (이 가상 머신에서) 직렬화되지 않은 개체만 직렬화한 후 시스템이 개체를 변환합니다. 바이트 시퀀스로 변환하여 출력
  • 객체가 직렬화된 경우 프로그램은 객체를 다시 재직렬화하는 대신 직렬화 번호를 직접 출력합니다.

import java.io.*;
public class WriteAllStar
{
  public static void main(String[] args)
  {
    try(
      // 创建一个ObjectOutputStream输出流
      ObjectOutputStream oos = new ObjectOutputStream(
        new FileOutputStream("allStar.txt")))
    {
      NbaPlayer player = new NbaPlayer("詹姆斯哈登", 13);
      AllStar allStar1 = new AllStar("西部全明星", player);
      AllStar allStar2 = new AllStar("首发后卫", player);
      // 依次将四个对象写入输出流
      oos.writeObject(allStar1);
      oos.writeObject(allStar2);
      oos.writeObject(player);
      oos.writeObject(allStar2);
    }
    catch (IOException ex)
    {
      ex.printStackTrace();
    }
  }
}

4개 객체가 출력 스트림에 기록되지만 실제로는 3개만 직렬화되며 시퀀스에 있는 두 AllStar 객체의 플레이어 참조는 실제로 동일한 NbaPlayer 개체입니다. 다음 프로그램은 직렬화된 파일의 객체를 읽습니다.

import java.io.*;
public class ReadAllStar
{
  public static void main(String[] args)
  {
    try(
      // 创建一个ObjectInputStream输出流
      ObjectInputStream ois = new ObjectInputStream(
        new FileInputStream("allStar.txt")))
    {
      // 依次读取ObjectInputStream输入流中的四个对象
      AllStar star1 = (AllStar)ois.readObject();
      AllStar star2 = (AllStar)ois.readObject();
      NbaPlayer player = (NbaPlayer)ois.readObject();
      AllStar star3 = (AllStar)ois.readObject();
      // 输出true
      System.out.println("star1的player引用和player是否相同:"
        + (star1.getPlayer() == player));
      // 输出true
      System.out.println("star2的player引用和player是否相同:"
        + (star2.getPlayer() == player));
      // 输出true
      System.out.println("star2和star3是否是同一个对象:"
        + (star2 == star3));
    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
  }
}

동일한 변경 가능한 Java 객체가 여러 번 직렬화되는 경우 처음으로 직렬화될 때만 Java 객체 바이트 시퀀스로 변환되어 출력됩니다

当使用Java序列化机制序列化可变对象时,只有第一次调用WriteObject()方法来输出对象时才会将对象转换成字节序列,并写入到ObjectOutputStream;即使在后面程序中,该对象的实例变量发生了改变,再次调用WriteObject()方法输出该对象时,改变后的实例变量也不会被输出

import java.io.*;

public class SerializeMutable
{
  public static void main(String[] args)
  {

    try(
      // 创建一个ObjectOutputStream输入流
      ObjectOutputStream oos = new ObjectOutputStream(
        new FileOutputStream("mutable.txt"));
      // 创建一个ObjectInputStream输入流
      ObjectInputStream ois = new ObjectInputStream(
        new FileInputStream("mutable.txt")))
    {
      NbaPlayer player = new NbaPlayer("斯蒂芬库里", 30);
      // 系统会player对象转换字节序列并输出
      oos.writeObject(player);
      // 改变per对象的name实例变量
      player.setName("塞斯库里");
      // 系统只是输出序列化编号,所以改变后的name不会被序列化
      oos.writeObject(player);
      NbaPlayer player1 = (NbaPlayer)ois.readObject();  //①
      NbaPlayer player2 = (NbaPlayer)ois.readObject();  //②
      // 下面输出true,即反序列化后player1等于player2
      System.out.println(player1 == player2);
      // 下面依然看到输出"斯蒂芬库里",即改变后的实例变量没有被序列化
      System.out.println(player2.getName());
    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
  }
}

以上就是Java 对象序列化 NIO NIO2详细介绍及解析的内容,更多相关内容请关注PHP中文网(www.php.cn)!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.