Java 프로그래밍에서의 정렬화 깊이 분석

22367 단어 Java서열화
자바는 질서정연한 형식이나 바이트 서열을 통해 자바 대상을 영구화하는 메커니즘을 제공합니다. 그 중에서 대상의 데이터, 그리고 대상의 유형, 그리고 대상에 저장된 데이터 형식을 포함합니다.
따라서 만약에 우리가 하나의 대상을 서열화했다면, 그것은 대상의 유형과 다른 정보를 통해 반서열화되고, 최종적으로 대상의 원형을 얻을 수 있다.
Object InputStream과 Object OutputStream 대상은 높은 등급의 흐름 대상으로 서열화와 반서열화 방법을 포함한다.
ObjectOutputStream은 여러 서열화된 대상을 가지고 있으며 가장 자주 사용하는 방법은 다음과 같습니다.
 

private void writeObject(ObjectOutputStream os) throws IOException
 {
   
 }
유사한 ObjectInputStream은 다음과 같은 방법을 제공합니다.
 

 private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException
 {
   
 }
그럼 서열화가 어디에 필요할까요?서열화는 일반적으로 네트워크를 통해 데이터를 전송하거나 대상을 파일에 저장해야 하는 장소에서 사용된다.여기서 말하는 데이터는 텍스트가 아니라 대상이다.
현재의 문제는 우리의 네트워크 구조와 하드디스크는 모두 바이트와 바이트만 식별할 수 있을 뿐 자바 대상을 식별할 수 없다는 것이다.
서열화는 자바 대상의value/states를 바이트로 번역하여 네트워크를 통해 전송하거나 저장하는 것이다.또한 반서열화는 바이트 코드를 읽고 자바 대상으로 번역하는 것이다.
serialVersionUID 개념
serialVersionUID는 Deserialization 과정에서 같은 객체가 로드될 수 있도록 보장하는 데 사용됩니다.serialVersionUID는 객체의 버전 제어에 사용됩니다.serialVersionUID in java serialization을 참고하여 더 많은 정보를 얻을 수 있습니다.
정렬의 경우:
단계는 다음과 같습니다.
열자 하나를 봅시다.
src->org.arpit.javapostsforlearning 직원 만들기.java
1.Employee.java 
 

package org.arpit.javapostsforlearning;
import java.io.Serializable;
public class Employee implements Serializable{
 
 int employeeId;
 String employeeName;
 String department;
  
 public int getEmployeeId() {
  return employeeId;
 }
 public void setEmployeeId(int employeeId) {
  this.employeeId = employeeId;
 }
 public String getEmployeeName() {
  return employeeName;
 }
 public void setEmployeeName(String employeeName) {
  this.employeeName = employeeName;
 }
 public String getDepartment() {
  return department;
 }
 public void setDepartment(String department) {
  this.department = department;
 }
}
보시다시피, 만약 어떤 종류를 서열화해야 한다면, Serializable 인터페이스를 실현해야 합니다. 이 인터페이스는 표기 인터페이스 (marker interface) 입니다.
자바의 마커 인터페이스(marker interface)는 필드나 방법이 없는 인터페이스입니다. 간단하게 말하면 자바에서 빈 인터페이스를 마커 인터페이스(marker interface)라고 합니다.
2.SerializeMain.java
 

package org.arpit.javapostsforlearning;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
 public class SerializeMain {
 
 /**
 * @author Arpit Mandliya
 */
 public static void main(String[] args) {
 
 Employee emp = new Employee();
 emp.setEmployeeId(101);
 emp.setEmployeeName("Arpit");
 emp.setDepartment("CS");
 try
 {
 FileOutputStream fileOut = new FileOutputStream("employee.ser");
 ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
 outStream.writeObject(emp);
 outStream.close();
 fileOut.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 }
 }
}
역정렬의 경우:
단계
가방 src->org.arpit.javapostsforlearning에서 DeserializeMain을 생성합니다.java
3.DeserializeMain.java
 

package org.arpit.javapostsforlearning;
import java.io.IOException;
import java.io.ObjectInputStream;
 
public class DeserializeMain {
 /**
 * @author Arpit Mandliya
 */
 public static void main(String[] args) {
 
 Employee emp = null;
  try
  {
   FileInputStream fileIn =new FileInputStream("employee.ser");
   ObjectInputStream in = new ObjectInputStream(fileIn);
   emp = (Employee) in.readObject();
   in.close();
   fileIn.close();
  }catch(IOException i)
  {
   i.printStackTrace();
   return;
  }catch(ClassNotFoundException c)
  {
   System.out.println("Employee class not found");
   c.printStackTrace();
   return;
  }
  System.out.println("Deserialized Employee...");
  System.out.println("Emp id: " + emp.getEmployeeId());
  System.out.println("Name: " + emp.getEmployeeName());
  System.out.println("Department: " + emp.getDepartment());
 }
}
4. 실행:
먼저 SerializeMain을 실행합니다.java, 그런 다음 DeserializeMain을 실행합니다.java, 당신은 다음과 같은 결과를 얻을 수 있습니다.
 

Deserialized Employee...
Emp id: 101
Name: Arpit
Department: CS
이렇게 해서 우리는employee 대상을 서열화하고 그것을 반서열화했다.이것은 보기에는 간단하지만 대상에 인용, 계승을 포함하면 상황이 복잡해진다.다음은 여러 장소에서 어떻게 서열화를 실현하는지 예를 하나하나 살펴보자.
사례 1 - 객체가 다른 객체를 참조하는 경우
우리는 이미 가장 간단한 서열화 예를 보았는데, 이제는 대상에 다른 대상을 인용한 장소를 어떻게 처리하는지 봅시다.우리는 어떻게 서열화해야 합니까?인용 대상도 서열화됩니까?네, 인용 대상을 현시적으로 서열화할 필요가 없습니다.모든 대상을 정렬할 때, 인용 대상을 포함하면, 자바 정렬화는 자동으로 대상의 전체 대상 그림을 정렬합니다.예를 들어,Employee는 현재address 대상을 인용하고,Address도 다른 대상(예를 들어,Home)을 인용합니다. 그러면 Employee 대상을 서열화할 때, 모든 다른 인용 대상, 예를 들어address와home은 자동으로 서열화됩니다.Address 클래스를 만들고 Address의 대상을 인용하여employee 클래스에 추가합니다.
Employee.java: 
 

package org.arpit.javapostsforlearning;
import java.io.Serializable;
 
public class Employee implements Serializable{
 
 int employeeId;
 String employeeName;
 String department;
 Address address;
 
 public int getEmployeeId() {
 return employeeId;
 }
 public void setEmployeeId(int employeeId) {
 this.employeeId = employeeId;
 }
 public String getEmployeeName() {
 return employeeName;
 }
 public void setEmployeeName(String employeeName) {
 this.employeeName = employeeName;
 }
 public String getDepartment() {
 return department;
 }
 public void setDepartment(String department) {
 this.department = department;
 }
 public Address getAddress() {
 return address;
 }
 public void setAddress(Address address) {
 this.address = address;
 }
}
org.arpit.javapostsforlearning 패키지에서 Address를 만듭니다.java
Address.java: 
 

package org.arpit.javapostsforlearning;
public class Address {
 
 int homeNo;
 String street;
 String city;
 public Address(int homeNo, String street, String city) {
 super();
 this.homeNo = homeNo;
 this.street = street;
 this.city = city;
 }
 public int getHomeNo() {
 return homeNo;
 }
 public void setHomeNo(int homeNo) {
 this.homeNo = homeNo;
 }
 public String getStreet() {
 return street;
 }
 public void setStreet(String street) {
 this.street = street;
 }
 public String getCity() {
 return city;
 }
 public void setCity(String city) {
 this.city = city;
 }
}
가방 org.arpit.javapostsforlearning에서 Serialize Deserialize Main을 만듭니다.java
SerializeDeserializeMain.java:
 

package org.arpit.javapostsforlearning;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
 
public class SerializeDeserializeMain {
 /**
 * @author Arpit Mandliya
 */
 public static void main(String[] args) {
 
 Employee emp = new Employee();
 emp.setEmployeeId(101);
 emp.setEmployeeName("Arpit");
 emp.setDepartment("CS");
 Address address=new Address(88,"MG road","Pune");
 emp.setAddress(address);
 //Serialize
 try
 {
 FileOutputStream fileOut = new FileOutputStream("employee.ser");
 ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
 outStream.writeObject(emp);
 outStream.close();
 fileOut.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 }
 
 //Deserialize
 emp = null;
 try
 {
 FileInputStream fileIn =new FileInputStream("employee.ser");
 ObjectInputStream in = new ObjectInputStream(fileIn);
 emp = (Employee) in.readObject();
 in.close();
 fileIn.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 return;
 }catch(ClassNotFoundException c)
 {
 System.out.println("Employee class not found");
 c.printStackTrace();
 return;
 }
 System.out.println("Deserialized Employee...");
 System.out.println("Emp id: " + emp.getEmployeeId());
 System.out.println("Name: " + emp.getEmployeeName());
 System.out.println("Department: " + emp.getDepartment());
 address=emp.getAddress();
 System.out.println("City :"+address.getCity());
 }
}
실행:
Serialize Deserialize Main을 실행하면java.너는 이런 결과를 얻을 수 있을 것이다.
 

java.io.NotSerializableException: org.arpit.javapostsforlearning.Address
 at java.io.ObjectOutputStream.writeObject0(Unknown Source)
 at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
 at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
 at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
 at java.io.ObjectOutputStream.writeObject0(Unknown Source)
 at java.io.ObjectOutputStream.writeObject(Unknown Source) 
우리는 어디가 잘못되었는지 설명할 것이다.Address 클래스도 serializable이어야 한다는 것을 잊어버렸습니다.그러면 Address 클래스는 serialzable 인터페이스를 계승해야 합니다.
Address.java:
 

import java.io.Serializable;
 
public class Address implements Serializable{
 
 int homeNo;
 String street;
 String city;
 public Address(int homeNo, String street, String city) {
 super();
 this.homeNo = homeNo;
 this.street = street;
 this.city = city;
 }
 public int getHomeNo() {
 return homeNo;
 }
 public void setHomeNo(int homeNo) {
 this.homeNo = homeNo;
 }
 public String getStreet() {
 return street;
 }
 public void setStreet(String street) {
 this.street = street;
 }
 public String getCity() {
 return city;
 }
 public void setCity(String city) {
 this.city = city;
 }
}
다시 실행:
Serialize Deserialize Main을 다시 실행하면java.너는 아래와 같은 결과를 얻을 수 있다
 

Deserialized Employee...
Emp id: 101
Name: Arpit
Department: CS
City :Pune
사례 2: 만약 우리가 인용 대상의 원본 코드에 접근할 수 없다면, (예를 들어 위의 Address 클래스의 원본 코드에 접근할 수 없다)
만약 우리가address 클래스에 접근할 수 없다면, 우리는address 클래스에서serializable 인터페이스를 어떻게 실현해야 합니까?다른 경로로 실현할 수 있습니까?그렇습니다. 다른 클래스를 만들고 Address를 계승한 다음serializable 인터페이스를 계승할 수 있습니다. 그러나 다음 경우에 이 방안은 실패합니다.
인용 클래스가final로 정의되면
만약 인용 클래스가 다른 비서열화된 대상을 인용한다면
그러면 Employee 객체를 어떻게 정렬해야 합니까?해결 방법은transient를 표시하는 것이다.만약 어떤 필드를 서열화할 필요가 없다면, 그것을transient로 표시하기만 하면 된다.
 
transient Address address
Employee 클래스에서address를transient로 표시한 후 프로그램을 실행합니다.반서열화 과정에서address 인용은null이 될 것이기 때문에nullPointerException을 받을 수 있습니다.
사례 3 - 인용 대상의 상태를 저장해야 한다면?(예:address 대상)
만약 당신이 반서열화 과정에서address를transient로 표시하면,null 결과를 되돌려줍니다.그러나 상태를 저장해야 한다면, address 대상을 서열화해야 합니다.Java 서열화는 특정한 서명의private 방법이 있으면 서열화와 반서열화 과정에서 호출되기 때문에 Employee 클래스의writeObject와readObject 방법을 다시 쓰고 Employee 대상의 서열화/반서열화 과정에서 호출됩니다.
Employee.java:

package org.arpit.javapostsforlearning;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
 
public class Employee implements Serializable{
 
 int employeeId;
 String employeeName;
 String department;
 transient Address address;
 
 public int getEmployeeId() {
 return employeeId;
 }
 public void setEmployeeId(int employeeId) {
 this.employeeId = employeeId;
 }
 public String getEmployeeName() {
 return employeeName;
 }
 public void setEmployeeName(String employeeName) {
 this.employeeName = employeeName;
 }
 public String getDepartment() {
 return department;
 }
 public void setDepartment(String department) {
 this.department = department;
 }
 public Address getAddress() {
 return address;
 }
 public void setAddress(Address address) {
 this.address = address;
 }
 
 private void writeObject(ObjectOutputStream os) throws IOException, ClassNotFoundException
 {
 try {
 os.defaultWriteObject();
 os.writeInt(address.getHomeNo());
 os.writeObject(address.getStreet());
 os.writeObject(address.getCity());
 }
 catch (Exception e)
 { e.printStackTrace(); }
 }
 
 private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException
 {
 try {
 is.defaultReadObject();
 int homeNo=is.readInt();
 String street=(String) is.readObject();
 String city=(String) is.readObject();
 address=new Address(homeNo,street,city);
 
 } catch (Exception e) { e.printStackTrace(); }
 }
}
또 하나 명심해야 할 것은 Object Input Stream이 데이터를 읽는 순서와 Object Output Stream이 데이터를 쓰는 순서가 일치한다는 것이다.
가방 org.arpit.javapostsforlearning에서 주소를 만듭니다.java
Address.java: 
 

package org.arpit.javapostsforlearning;
import java.io.Serializable;
 
public class Address {
 
 int homeNo;
 String street;
 String city;
 
 
 public Address(int homeNo, String street, String city) {
 super();
 this.homeNo = homeNo;
 this.street = street;
 this.city = city;
 }
 public int getHomeNo() {
 return homeNo;
 }
 public void setHomeNo(int homeNo) {
 this.homeNo = homeNo;
 }
 public String getStreet() {
 return street;
 }
 public void setStreet(String street) {
 this.street = street;
 }
 public String getCity() {
 return city;
 }
 public void setCity(String city) {
 this.city = city;
 }
}
가방 org.arpit.javapostsforlearning에서 SerializeDeserializeMain을 만듭니다.java
SerializeDeserializeMain.java:
 

package org.arpit.javapostsforlearning;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
 
public class SerializeDeserializeMain {
 /**
 * @author Arpit Mandliya
 */
 public static void main(String[] args) {
 
 Employee emp = new Employee();
 emp.setEmployeeId(101);
 emp.setEmployeeName("Arpit");
 emp.setDepartment("CS");
 Address address=new Address(88,"MG road","Pune");
 emp.setAddress(address);
 //Serialize
 try
 {
 FileOutputStream fileOut = new FileOutputStream("employee.ser");
 ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
 outStream.writeObject(emp);
 outStream.close();
 fileOut.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 }
 
 //Deserialize
 emp = null;
 try
 {
 FileInputStream fileIn =new FileInputStream("employee.ser");
 ObjectInputStream in = new ObjectInputStream(fileIn);
 emp = (Employee) in.readObject();
 in.close();
 fileIn.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 return;
 }catch(ClassNotFoundException c)
 {
 System.out.println("Employee class not found");
 c.printStackTrace();
 return;
 }
 System.out.println("Deserialized Employee...");
 System.out.println("Emp id: " + emp.getEmployeeId());
 System.out.println("Name: " + emp.getEmployeeName());
 System.out.println("Department: " + emp.getDepartment());
 address=emp.getAddress();
 System.out.println("City :"+address.getCity());
 }
}
실행:
Serialize Deserialize Main을 실행하면java.당신은 다음과 같은 결과를 얻을 수 있습니다.
 

Deserialized Employee...
Emp id: 101
Name: Arpit
Department: CS
City :Pune
이제 우리는address 대상의 상태를 얻었다. 그것이 서열화되기 전과 같다.
정렬화된 상속:
이제 상속이 어떻게 서열화에 영향을 미치는지 봅시다.부류가 서열화되든 안 되든 간에 이것은 많은 예를 이끌어 낼 것이다.만약 부류가 서열화되지 않는다면, 우리는 어떻게 처리할 것이며, 그것이 어떻게 작동할 것인가.예를 봅시다.
우리는 Person을 만들 것이다.java, Employee의 상위 클래스입니다.
사례 4: 상위 클래스가 정렬된 경우
만약 부류가 서열화할 수 있다면, 모든 계승 클래스는 서열화할 수 있을 것이다.
사례 5: 상위 클래스가 정렬되지 않은 경우?
만약 부류가 비서열화된다면, 우리의 처리 방법은 매우 달라질 것이다.
만약 부류가 서열화되지 않는다면, 그것은 반드시 매개 변수 구조 함수가 없을 것이다.
Person.java 
 

package org.arpit.javapostsforlearning;
public class Person {
 
 String name="default";
 String nationality;
 
 public Person()
 {
 System.out.println("Person:Constructor");
 }
 
 public Person(String name, String nationality) {
 super();
 this.name = name;
 this.nationality = nationality;
 }
 
 public String getName() {
 return name;
 }
 
 public void setName(String name) {
 this.name = name;
 }
 
 public String getNationality() {
 return nationality;
 }
 
 public void setNationality(String nationality) {
 this.nationality = nationality;
 }
 
}
가방 org.arpit.javapostsforlearning에서 Employee를 만듭니다.java
Employee.java:
 

package org.arpit.javapostsforlearning;
import java.io.Serializable;
 
public class Employee extends Person implements Serializable{
 
 int employeeId;
 String department;
 
 public Employee(int employeeId,String name,String department,String nationality)
 {
 super(name,nationality);
 this.employeeId=employeeId;
 this.department=department;
 System.out.println("Employee:Constructor");
 }
 
 public int getEmployeeId() {
 return employeeId;
 }
 public void setEmployeeId(int employeeId) {
 this.employeeId = employeeId;
 }
 
 public String getDepartment() {
 return department;
 }
 public void setDepartment(String department) {
 this.department = department;
 }
}
org.arpit.javapostsforlearning 패키지에서 SerializeDeserializeMain을 만듭니다.java
SerializeDeserializeMain.java:


package org.arpit.javapostsforlearning;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
 
public class SerializeDeserializeMain {
 
 /**
 * @author Arpit Mandliya
 */
 public static void main(String[] args) {
 
 //Serialize
 Employee emp = new Employee(101,"Arpit","CS","Indian");
 System.out.println("Before serializing");
 System.out.println("Emp id: " + emp.getEmployeeId());
 System.out.println("Name: " + emp.getName());
 System.out.println("Department: " + emp.getDepartment());
 System.out.println("Nationality: " + emp.getNationality());
 System.out.println("************");
 System.out.println("Serializing");
 try
 {
 FileOutputStream fileOut = new FileOutputStream("employee.ser");
 ObjectOutputStream outStream = new ObjectOutputStream(fileOut);
 outStream.writeObject(emp);
 outStream.close();
 fileOut.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 }
 
 //Deserialize
 System.out.println("************");
 System.out.println("Deserializing");
 emp = null;
 try
 {
 FileInputStream fileIn =new FileInputStream("employee.ser");
 ObjectInputStream in = new ObjectInputStream(fileIn);
 emp = (Employee) in.readObject();
 in.close();
 fileIn.close();
 }catch(IOException i)
 {
 i.printStackTrace();
 return;
 }catch(ClassNotFoundException c)
 {
 System.out.println("Employee class not found");
 c.printStackTrace();
 return;
 }
 System.out.println("After serializing");
 System.out.println("Emp id: " + emp.getEmployeeId());
 System.out.println("Name: " + emp.getName());
 System.out.println("Department: " + emp.getDepartment());
 System.out.println("Nationality: " + emp.getNationality());
 }
}
실행:
Serialize Deserialize Main을 실행하면자바 후에 다음과 같은 출력을 얻을 수 있습니다. 만약에 부류가 서열화되지 않으면 반서열화 과정에서 부류에 계승된 모든 실례 변수 값은 비서열화 구조 함수를 호출하여 초기화됩니다.여기name는person에 계승되기 때문에 반서열화 과정에서name는 기본값으로 초기화됩니다.
사례 6 - 부모 클래스가 서열화될 수 있지만, 계승 클래스가 서열화될 필요는 없습니다.
계승 클래스가 서열화되기를 원하지 않는다면, writeObject () 와readObject () 방법을 실현하고, NotSerializableException 이상을 던져야 합니다.
사례 7 - 정적 변수를 정렬할 수 있습니까?
안돼.정적 변수는 클래스 레벨이기 때문에 대상 레벨이 아닙니다. 대상을 서열화할 때 정적 변수를 서열화할 수 없습니다.
요약:
  • 서열화는 자바 대상의values/states가 바이트로 바뀌어 네트워크에서 전송되거나 저장되는 과정이다.또한 반서열화는 바이트 코드를 대응하는 대상으로 번역하는 과정이다
  • 서열화의 장점은 JVM의 독립성, 즉 하나의 대상이 하나의 플랫폼에서 서열화되고 다른 플랫폼에서 반서열화된다는 것이다
  • 만약 당신이 어떤 대상을 서열화해야 한다면, 표기 인터페이스 Serializable을 실현해야 합니다..
  • 자바의 마커 인터페이스(Marker interface)는 필드나 방법이 없는 인터페이스이거나 더 간단하게 말하면 빈 인터페이스이다
  • serialVersionUID는 Deserialization 과정에서 같은 객체가 로드될 수 있도록 보장하는 데 사용됩니다.serialVersionUID는 객체의 버전 제어에 사용됩니다
  • 인용 대상을 포함하는 모든 대상을 서열화해야 한다면, 자바는 자동으로 이 대상의 전체 대상 그림을 서열화한다..
  • 만약 당신이 어떤 필드를 서열화하기를 원하지 않는다면, 그것을trasient라고 표시할 수 있습니다
  • 만약에 부류가 서열화된다면 그 계승류도 서열화될 것이다..
  • 만약에 부류가 비서열화된다면 반서열화 과정에서 부류에 계승된 모든 실례 변수 값은 비서열화된 구조기를 호출하여 초기화될 것이다
  • 하위 클래스가 서열화되기를 원한다면 writeObject () 와readObject () 방법을 실현하고 이 두 가지 방법에서 NotSerializableException 이상을 던져야 합니다
  • 정적 변수를 서열화할 수 없습니다..
  • 좋은 웹페이지 즐겨찾기