development

객체 직렬화 란 무엇입니까?

big-blog 2020. 2. 27. 22:24
반응형

객체 직렬화 란 무엇입니까?


"개체 직렬화"란 무엇입니까? 몇 가지 예를 들어 설명해 주시겠습니까?


직렬화는 객체를 일련의 바이트로 변환하여 객체를 영구 저장소에 쉽게 저장하거나 통신 링크를 통해 스트리밍 할 수 있습니다. 그런 다음 바이트 스트림을 역 직렬화하여 원래 객체의 복제본으로 변환 할 수 있습니다.


직렬화를 객체 인스턴스를 일련의 바이트로 변환하는 프로세스라고 생각할 수 있습니다 (구현에 따라 이진일 수도 있고 아닐 수도 있음).

하나의 JVM에서 다른 JVM으로 네트워크를 통해 하나의 오브젝트 데이터를 전송하려는 경우 매우 유용합니다.

Java에서는 직렬화 메커니즘이 플랫폼에 내장되어 있지만 직렬화 가능 인터페이스를 구현하여 오브젝트를 직렬화 할 수 있도록해야합니다.

속성을 transient 로 표시하여 객체의 일부 데이터가 직렬화되는 것을 방지 할 수도 있습니다 .

마지막으로 기본 메커니즘을 무시하고 고유 한 메커니즘을 제공 할 수 있습니다. 이것은 특별한 경우에 적합 할 수 있습니다. 이를 위해 java숨겨진 기능 중 하나를 사용 합니다.

직렬화되는 것은 클래스 정의가 아니라 객체 또는 내용의 "값"이라는 점에 유의해야합니다. 따라서 메소드는 직렬화되지 않습니다.

다음은 쉽게 읽을 수있는 주석이 포함 된 매우 기본적인 샘플입니다.

import java.io.*;
import java.util.*;

// This class implements "Serializable" to let the system know
// it's ok to do it. You as programmer are aware of that.
public class SerializationSample implements Serializable {

    // These attributes conform the "value" of the object.

    // These two will be serialized;
    private String aString = "The value of that string";
    private int    someInteger = 0;

    // But this won't since it is marked as transient.
    private transient List<File> unInterestingLongLongList;

    // Main method to test.
    public static void main( String [] args ) throws IOException  { 

        // Create a sample object, that contains the default values.
        SerializationSample instance = new SerializationSample();

        // The "ObjectOutputStream" class has the default 
        // definition to serialize an object.
        ObjectOutputStream oos = new ObjectOutputStream( 
                               // By using "FileOutputStream" we will 
                               // Write it to a File in the file system
                               // It could have been a Socket to another 
                               // machine, a database, an in memory array, etc.
                               new FileOutputStream(new File("o.ser")));

        // do the magic  
        oos.writeObject( instance );
        // close the writing.
        oos.close();
    }
}

이 프로그램을 실행하면 "o.ser"파일이 생성되고 어떤 일이 발생했는지 확인할 수 있습니다.

someInteger을 예를 들어 Integer.MAX_VALUE변경하면 출력을 비교하여 차이가 무엇인지 확인할 수 있습니다.

그 차이점을 정확하게 보여주는 스크린 샷은 다음과 같습니다.

대체 텍스트

차이점을 알 수 있습니까? ;)

Java 직렬화에는 추가 관련 필드가 있습니다. serialversionUID 이지만 이미 너무 길어서 다루기가 어렵 습니다.


Java를 처음 접하는 사람들을 위해 매우 높은 수준의 이해를 추가하여 6 년 된 질문에 대답

직렬화 란 무엇입니까?

객체를 바이트로 변환하고 바이트를 다시 객체로 변환 (직렬화).

직렬화는 언제 사용됩니까?

우리가 객체를 유지하고 싶을 때. JVM의 수명을 넘어서 객체가 존재하기를 원할 때.

실제 예 :

ATM : 계정 소유자가 ATM을 통해 서버에서 돈을 인출하려고하면 인출 세부 사항과 같은 계정 소유자 정보가 직렬화되어 세부 사항이 직렬화 해제되어 조작을 수행하는 데 사용되는 서버로 전송됩니다.

Java에서 직렬화가 수행되는 방법

  1. 구현 java.io.Serializable(어떤 방법을 구현하지 할 수 있도록 마커 인터페이스) 인터페이스를.

  2. 객체 지속 : java.io.ObjectOutputStream하위 레벨 바이트 스트림을 감싸는 래퍼 인 필터 스트림 인 class를 사용 합니다 (파일 시스템에 객체를 쓰거나 네트워크 와이어를 통해 평탄화 된 객체를 전송하고 다른 쪽에서 다시 작성).

    • writeObject(<<instance>>) -객체를 작성
    • readObject() -직렬화 된 객체를 읽는다

생각해 내다:

객체를 직렬화하면 객체의 클래스 파일이나 메소드가 아니라 객체의 상태 만 저장됩니다.

2 바이트 객체를 직렬화하면 51 바이트 직렬화 파일이 표시됩니다.

개체의 직렬화 및 역 직렬화 방법을 단계별로 설명합니다.

답 : 51 바이트 파일로 어떻게 변환 했습니까?

  • 먼저 직렬화 스트림 매직 데이터 (STREAM_MAGIC = "AC ED"및 STREAM_VERSION = JVM의 버전)를 씁니다.
  • 그런 다음 인스턴스와 연관된 클래스의 메타 데이터 (클래스 길이, 클래스 이름, serialVersionUID)를 작성합니다.
  • 그런 다음을 찾을 때까지 슈퍼 클래스의 메타 데이터를 재귀 적으로 작성합니다 java.lang.Object.
  • 그런 다음 인스턴스와 연관된 실제 데이터로 시작합니다.
  • 마지막으로 인스턴스와 관련된 객체의 데이터를 메타 데이터에서 실제 컨텐츠로 씁니다.

Java Serialization에 대한 자세한 내용을 보려면이 링크 를 확인 하십시오 .

편집 : 읽을 하나 더 좋은 링크 .

이것은 몇 가지 자주 묻는 질문에 대한 답변입니다.

  1. 클래스의 필드를 직렬화하지 않는 방법
    답변 : 임시 키워드 사용

  2. 자식 클래스가 직렬화되면 부모 클래스가 직렬화됩니까?
    답변 : 아니오, 부모가 확장 할 수없는 경우 직렬화 가능 인터페이스 부모 필드는 직렬화되지 않습니다.

  3. 부모가 직렬화되면 하위 클래스가 직렬화됩니까?
    답변 : 예. 기본적으로 자식 클래스도 직렬화됩니다.

  4. 자식 클래스가 직렬화되는 것을 피하는 방법은 무엇입니까?
    답변 : a. writeObject 및 readObject 메소드를 대체하고 throw하십시오 NotSerializableException.

    비. 또한 자식 클래스에서 모든 필드를 일시적으로 표시 할 수 있습니다.

  5. Thread, OutputStream 및 해당 서브 클래스 및 Socket과 같은 일부 시스템 레벨 클래스는 직렬화 할 수 없습니다.

직렬화는 메모리에서 "라이브"개체를 가져 와서 어딘가에 저장 (예 : 메모리, 디스크) 한 후 나중에 다시 라이브 개체로 "직렬화 해제"할 수있는 형식으로 변환합니다.


@OscarRyz가 제시하는 방식이 마음에 들었습니다. 비록 여기 에 @amitgupta에 의해 쓰여진 직렬화 이야기를 계속하고 있지만 .

로봇 클래스 구조를 알고 데이터를 직렬화 했음에도 지구 과학자는 로봇을 작동시킬 수있는 데이터를 직렬화 해제 할 수 없었습니다.

Exception in thread "main" java.io.InvalidClassException:
SerializeMe; local class incompatible: stream classdesc
:

화성의 과학자들은 완전한 지불을 기다리고있었습니다. 결제가 완료되면 화성의 과학자들은 지구의 과학자들과 serialversionUID공유했습니다 . 지구의 과학자는 그것을 로봇 클래스로 설정했고 모든 것이 잘되었습니다.


내 블로그에서 내 2 센트 :

다음은 직렬화에 대한 자세한 설명입니다 . (나의 블로그)

직렬화 :

직렬화는 객체의 상태를 유지하는 프로세스입니다. 일련의 바이트 형식으로 표시되고 저장됩니다. 파일에 저장할 수 있습니다. 파일에서 객체의 상태를 읽고 복원하는 프로세스를 역 직렬화라고합니다.

직렬화의 필요성은 무엇입니까?

현대 건축에서는 항상 객체 상태를 저장 한 다음 검색해야합니다. 예를 들어, 최대 절전 모드에서 객체를 저장하려면 클래스를 Serializable로 만들어야합니다. 그것은 일단 객체 상태가 바이트 형태로 저장되면 다른 시스템으로 전송되어 상태에서 읽고 클래스를 검색 할 수 있다는 것입니다. 객체 상태는 데이터베이스 또는 다른 jvm 또는 별도의 구성 요소에서 올 수 있습니다. Serialization의 도움으로 Object 상태를 검색 할 수 있습니다.

코드 예 및 설명 :

먼저 아이템 클래스를 보자 :

public class Item implements Serializable{

    /**
    *  This is the Serializable class
    */
    private static final long serialVersionUID = 475918891428093041L;
    private Long itemId;
    private String itemName;
    private transient Double itemCostPrice;
    public Item(Long itemId, String itemName, Double itemCostPrice) {
        super();
        this.itemId = itemId;
        this.itemName = itemName;
        this.itemCostPrice = itemCostPrice;
      }

      public Long getItemId() {
          return itemId;
      }

     @Override
      public String toString() {
          return "Item [itemId=" + itemId + ", itemName=" + itemName + ", itemCostPrice=" + itemCostPrice + "]";
       }


       public void setItemId(Long itemId) {
           this.itemId = itemId;
       }

       public String getItemName() {
           return itemName;
       }
       public void setItemName(String itemName) {
            this.itemName = itemName;
        }

       public Double getItemCostPrice() {
            return itemCostPrice;
        }

        public void setItemCostPrice(Double itemCostPrice) {
             this.itemCostPrice = itemCostPrice;
        }
}

위 코드에서 Item 클래스가 Serializable을 구현 하고 있음을 알 수 있습니다 .

클래스를 직렬화 할 수있는 인터페이스입니다.

이제 serialVersionUID 라는 변수가 Long 변수로 초기화 된 것을 볼 수 있습니다 . 이 숫자는 클래스 상태 및 클래스 속성에 따라 컴파일러에서 계산됩니다. 이것은 파일에서 객체의 상태를 읽을 때 jvm이 객체의 상태를 식별하는 데 도움이되는 숫자입니다.

이를 위해 공식 Oracle Documentation을 살펴볼 수 있습니다.

직렬화 런타임은 직렬화 가능 오브젝트의 송신자 및 수신자가 직렬화와 호환되는 해당 오브젝트에 대한 클래스를로드했는지 검증하기 위해 직렬화 해제 중에 사용되는 직렬 버전 UID라고하는 버전 번호를 각 직렬화 가능 클래스와 연관시킵니다. 수신자가 해당 송신자의 클래스와 다른 serialVersionUID를 가진 객체의 클래스를로드 한 경우 역 직렬화는 InvalidClassException을 발생시킵니다. 직렬화 가능 클래스는 static, final 및 long 유형이어야하는 "serialVersionUID"라는 필드를 선언하여 고유 한 serialVersionUID를 명시 적으로 선언 할 수 있습니다. ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; 직렬화 가능 클래스가 serialVersionUID를 명시 적으로 선언하지 않으면 직렬화 런타임은 Java (TM) 객체 직렬화 스펙에 설명 된대로 클래스의 다양한 측면을 기반으로 해당 클래스의 기본 serialVersionUID 값을 계산합니다. 그러나 기본 serialVersionUID 계산은 컴파일러 구현에 따라 달라질 수있는 클래스 세부 정보에 매우 민감하므로 역 직렬화 중에 예기치 않은 InvalidClassExceptions가 발생할 수 있으므로 모든 serializable 클래스는 serialVersionUID 값을 명시 적으로 선언하는 것이 좋습니다. 따라서 다른 Java 컴파일러 구현에서 일관된 serialVersionUID 값을 보장하려면 직렬화 가능 클래스가 명시 적 serialVersionUID 값을 선언해야합니다. 또한 명시적인 serialVersionUID 선언은 가능한 경우 전용 수정자를 사용하는 것이 좋습니다.

당신이 우리가 사용한 또 다른 키워드가 있다는 것을 알아 차렸다면 과도 합니다.

필드를 직렬화 할 수없는 경우 일시적으로 표시해야합니다. 여기서 itemCostPrice 를 일시적으로 표시하고 파일에 쓰지 않기를 원합니다.

이제 파일에 객체의 상태를 작성하고 거기서 읽는 방법을 살펴 보겠습니다.

public class SerializationExample {

    public static void main(String[] args){
        serialize();
       deserialize();
    } 

    public static void serialize(){

         Item item = new Item(1L,"Pen", 12.55);
         System.out.println("Before Serialization" + item);

         FileOutputStream fileOut;
         try {
             fileOut = new FileOutputStream("/tmp/item.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(item);
             out.close();
             fileOut.close();
             System.out.println("Serialized data is saved in /tmp/item.ser");
           } catch (FileNotFoundException e) {

                  e.printStackTrace();
           } catch (IOException e) {

                  e.printStackTrace();
           }
      }

    public static void deserialize(){
        Item item;

        try {
                FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
                ObjectInputStream in = new ObjectInputStream(fileIn);
                item = (Item) in.readObject();
                System.out.println("Serialized data is read from /tmp/item.ser");
                System.out.println("After Deserialization" + item);
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        } catch (IOException e) {
               e.printStackTrace();
        } catch (ClassNotFoundException e) {
               e.printStackTrace();
        }
     }
}

위에서 우리는 객체의 직렬화와 역 직렬화의 예를 볼 수 있습니다.

이를 위해 두 가지 클래스를 사용했습니다. 객체를 직렬화하기 위해 ObjectOutputStream을 사용했습니다. writeObject 메소드를 사용하여 파일에 오브젝트를 작성했습니다.

역 직렬화를 위해 파일에서 객체를 읽는 ObjectInputStream을 사용했습니다. readObject를 사용하여 파일에서 오브젝트 데이터를 읽습니다.

위 코드의 출력은 다음과 같습니다.

Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]

공지 사항 것을 itemCostPrice 직렬화 된 객체는 널 (null) 이 작성되지 않았습니다으로가.

이 기사의 1 부에서 Java 직렬화의 기본 사항에 대해 이미 논의했다.

이제 자세히 살펴보고 작동 방식을 살펴 보겠습니다.

먼저 serialversionuid 부터 시작하겠습니다 .

의 serialVersionUID가 직렬화 가능 클래스의 버전 컨트롤로 사용됩니다.

serialVersionUID를 명시 적으로 선언하지 않으면 JVM은 Serializable 클래스의 다양한 속성에 따라 자동으로이를 수행합니다.

serialversionuid 계산의 Java 알고리즘 (자세한 내용은 여기를 참조하십시오)

  1. 클래스 이름
    1. 클래스 수정자는 32 비트 정수로 작성되었습니다.
    2. 이름별로 정렬 된 각 인터페이스의 이름입니다.
    3. 필드 이름별로 정렬 된 클래스의 각 필드 (개인 정적 및 개인 임시 필드 제외 : 필드 이름, 32 비트 정수로 작성된 필드 수정 자, 필드 설명자).
    4. 클래스 이니셜 라이저가 존재하면 다음을 작성하십시오. 메소드 이름.
    5. 메소드의 수정 자 java.lang.reflect.Modifier.STATIC은 32 비트 정수로 작성됩니다.
    6. 메소드의 기술자, () V.
    7. 메소드 이름 및 서명별로 정렬 된 각각의 개인용이 아닌 생성자에 대해 다음을 수행하십시오. 메소드의 수정자는 32 비트 정수로 작성됩니다. 메소드의 설명자
    8. 메소드 이름 및 서명별로 정렬 된 각각의 비 개인 메소드에 대해 : 메소드 이름. 메소드의 수정자는 32 비트 정수로 작성됩니다. 메소드의 설명자
    9. SHA-1 알고리즘은 DataOutputStream에 의해 생성 된 바이트 스트림에서 실행되며 5 개의 32 비트 값 sha [0..4]를 생성합니다. 해시 값은 SHA-1 메시지 요약의 첫 번째 및 두 번째 32 비트 값으로 구성됩니다. 메시지 다이제스트의 결과, 5 개의 32 비트 단어 H0 H1 H2 H3 H4가 sha라는 5 개의 int 값의 배열에 있으면 해시 값은 다음과 같이 계산됩니다.
    long hash = ((sha[0] >>> 24) & 0xFF) |
>            ((sha[0] >>> 16) & 0xFF) << 8 |
>            ((sha[0] >>> 8) & 0xFF) << 16 |
>            ((sha[0] >>> 0) & 0xFF) << 24 |
>            ((sha[1] >>> 24) & 0xFF) << 32 |
>            ((sha[1] >>> 16) & 0xFF) << 40 |
>            ((sha[1] >>> 8) & 0xFF) << 48 |
>        ((sha[1] >>> 0) & 0xFF) << 56;

자바의 직렬화 알고리즘

객체를 직렬화하는 알고리즘은 다음과 같습니다.
1. 인스턴스와 관련된 클래스의 메타 데이터를 작성합니다.
2. java.lang.object를 찾을 때까지 수퍼 클래스의 설명을 재귀 적으로 작성합니다 .
3. 메타 데이터 정보 쓰기가 끝나면 인스턴스와 연결된 실제 데이터로 시작합니다. 그러나 이번에는 최상위 슈퍼 클래스에서 시작합니다.
4. 최소 수퍼 클래스에서 가장 파생 된 클래스까지 인스턴스와 연관된 데이터를 반복해서 씁니다.

명심해야 할 것들 :

  1. 클래스의 정적 필드는 직렬화 할 수 없습니다.

    public class A implements Serializable{
         String s;
         static String staticString = "I won't be serializable";
    }
    
  2. 읽기 버전에서 serialversionuid가 다른 경우 InvalidClassException예외 발생합니다.

  3. 클래스가 직렬화 가능을 구현하면 모든 하위 클래스도 직렬화 가능합니다.

    public class A implements Serializable {....};
    
    public class B extends A{...} //also Serializable
    
  4. 클래스에 다른 클래스에 대한 참조가있는 경우 모든 참조는 직렬화 가능해야합니다. 그렇지 않으면 직렬화 프로세스가 수행되지 않습니다. 이러한 경우 런타임에 NotSerializableException 이 발생합니다.

예 :

public class B{
     String s,
     A a; // class A needs to be serializable i.e. it must implement Serializable
}

직렬화는 Java에서 객체를 유지하는 것을 의미합니다. 객체의 상태를 저장하고 나중에 상태를 다시 빌드하려는 경우 (다른 JVM에있을 수 있음) 직렬화를 사용할 수 있습니다.

객체의 속성은 저장 만됩니다. 객체를 다시 부활 시키려면 멤버 변수 만 저장되고 멤버 함수는 저장되지 않기 때문에 클래스 파일이 있어야합니다.

예 :

ObjectInputStream oos = new ObjectInputStream(                                 
                                 new FileInputStream(  new File("o.ser")) ) ;
SerializationSample SS = (SearializationSample) oos.readObject();

Searializable은 클래스가 직렬화 가능함을 표시하는 마커 인터페이스입니다. 마커 인터페이스는 빈 인터페이스 일 뿐이며 해당 인터페이스를 사용하면이 클래스를 직렬화 할 수 있음을 JVM에 알립니다.


직렬화는 하드 드라이브에 저장 될 수 있도록 객체의 상태를 비트로 변환하는 프로세스입니다. 동일한 객체를 역 직렬화하면 나중에 해당 상태가 유지됩니다. 손으로 객체의 속성을 저장하지 않고도 객체를 다시 만들 수 있습니다.

http://en.wikipedia.org/wiki/Serialization


직렬화는 파일이나 메모리 버퍼와 같은 저장 매체에 객체를 저장하거나 이진 형태로 네트워크 연결을 통해 전송하는 프로세스입니다. 직렬화 된 객체는 JVM과 무관하며 모든 JVM에서 다시 직렬화 할 수 있습니다. 이 경우 "메모리에있는"Java 객체 상태는 바이트 스트림으로 변환됩니다. 이 유형의 파일은 사용자가 이해할 수 없습니다. JVM (Java Virtual Machine)에 의해 재사용되는 특수한 유형의 객체입니다. 객체를 직렬화하는이 과정을 객체를 수축 또는 마샬링이라고합니다.

직렬화 할 객체는 java.io.Serializable인터페이스 를 구현해야합니다 . 객체의 기본 직렬화 메커니즘은 객체의 클래스, 클래스 서명 및 모든 비 일시적 필드와 비 정적 필드의 값을 씁니다.

class ObjectOutputStream extends java.io.OutputStream implements ObjectOutput,

ObjectOutputinterface는 인터페이스를 확장하고 DataOutput객체를 직렬화하고 바이트를 파일에 쓰는 방법을 추가합니다. ObjectOutputStream확장 java.io.OutputStream및 구현은 ObjectOutput인터페이스. 객체, 배열 및 기타 값을 스트림으로 직렬화합니다. 따라서의 생성자 ObjectOutputStream는 다음과 같이 작성됩니다.

ObjectOutput ObjOut = new ObjectOutputStream(new FileOutputStream(f));

위의 코드는 의 인스턴스를 매개 변수로 ObjectOutput사용하는 ObjectOutputStream( )생성자를 사용 하여 클래스 의 인스턴스를 만드는 데 사용되었습니다 FileOuputStream.

ObjectOutput인터페이스는 구현에 의해 사용되는 ObjectOutputStream클래스를. ObjectOutputStream객체를 직렬화하는 구성된다.

자바에서 객체의 역 직렬화

직렬화의 반대 동작을 직렬화 해제라고합니다. 즉, 일련의 바이트에서 데이터를 추출하는 것을 직렬화 해제라고합니다.이를 직렬화 또는 비 정렬 화라고도합니다.

ObjectInputStream인터페이스를 확장 java.io.InputStream하고 구현 ObjectInput합니다. 입력 스트림에서 객체, 배열 및 기타 값을 역 직렬화합니다. 따라서의 생성자 ObjectInputStream는 다음과 같이 작성됩니다.

ObjectInputStream obj = new ObjectInputStream(new FileInputStream(f));

위의 프로그램 코드는 ObjectInputStream클래스에 의해 직렬화 된 파일을 직렬화 해제하기 위해 클래스 의 인스턴스를 작성합니다 ObjectInputStream. 위의 코드 FileInputStreamObjectInputStream()생성자가 입력 스트림을 필요로 하기 때문에 역 직렬화되어야하는 지정된 파일 객체를 보유하는 클래스 의 인스턴스를 사용하여 인스턴스를 만듭니다 .


직렬화는 Java 객체를 바이트 배열로 변환 한 다음 보존 된 상태로 다시 객체로 변환하는 프로세스입니다. 네트워크를 통해 객체를 전송하거나 디스크로 캐시하는 것과 같은 다양한 용도에 유용합니다.

에서 더 많은 읽기 아주 잘 프로세스의 일부를 프로그래밍 설명합니다이 짧은 기사 다음에까지 이동 직렬화의 javadoc . 이 관련 질문 을 읽고 싶을 수도 있습니다 .


파일을 오브젝트로 리턴하십시오. http://www.tutorialspoint.com/java/java_serialization.htm

        import java.io.*;

        public class SerializeDemo
        {
           public static void main(String [] args)
           {
              Employee e = new Employee();
              e.name = "Reyan Ali";
              e.address = "Phokka Kuan, Ambehta Peer";
              e.SSN = 11122333;
              e.number = 101;

              try
              {
                 FileOutputStream fileOut =
                 new FileOutputStream("/tmp/employee.ser");
                 ObjectOutputStream out = new ObjectOutputStream(fileOut);
                 out.writeObject(e);
                 out.close();
                 fileOut.close();
                 System.out.printf("Serialized data is saved in /tmp/employee.ser");
              }catch(IOException i)
              {
                  i.printStackTrace();
              }
           }
        }

    import java.io.*;
    public class DeserializeDemo
    {
       public static void main(String [] args)
       {
          Employee e = null;
          try
          {
             FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
             ObjectInputStream in = new ObjectInputStream(fileIn);
             e = (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("Name: " + e.name);
          System.out.println("Address: " + e.address);
          System.out.println("SSN: " + e.SSN);
          System.out.println("Number: " + e.number);
        }
    }

자바 객체 직렬화

여기에 이미지 설명을 입력하십시오

SerializationJava 객체의 그래프를 storage ( to disk file) 또는 transmission ( across a network)을 위해 바이트 배열로 변환 한 다음 역 직렬화 를 사용하여 객체의 그래프 복원 할 수 있는 메커니즘 입니다. 참조 공유 메커니즘을 사용하여 오브젝트의 그래프가 올바르게 복원됩니다. 그러나 저장하기 전에 입력 파일 / 네트워크의 serialVersionUID와 .class 파일 serialVersionUID가 동일한 지 확인하십시오. 그렇지 않으면를 던지십시오 java.io.InvalidClassException.

버전이 지정된 각 클래스는 스트림을 작성할 수 있고 읽을 수있는 원래 클래스 버전을 식별해야합니다. 예를 들어, 버전이 지정된 클래스는 다음을 선언해야합니다.

serialVersionUID 구문

// ANY-ACCESS-MODIFIER static final long serialVersionUID = (64-bit has)L;
private static final long serialVersionUID = 3487495895819393L;

serialVersionUID 는 직렬화 프로세스에 필수적입니다. 그러나 개발자가 Java 소스 파일에 추가하는 것은 선택 사항입니다. serialVersionUID가 포함되어 있지 않으면 serialization 런타임은 serialVersionUID를 생성하여 클래스와 연결합니다. 직렬화 된 객체는이 serialVersionUID를 다른 데이터와 함께 포함합니다.

– 모든 직렬화 가능 클래스는 serialVersionUID를 명시 적으로 선언 since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations하므로 직렬화 해제 중에 예기치 않은 serialVersionUID 충돌이 발생하여 직렬화 해제가 실패 할 수 있습니다.

직렬화 가능 클래스 검사

여기에 이미지 설명을 입력하십시오


Java 객체는 직렬화 만 가능합니다. 클래스 또는 수퍼 클래스를 구현하는 하나의 경우 를 java.io.Serializable 인터페이스 또는 하위 인터페이스 java.io.Externalizable의 .

  • 객체를 성공적으로 직렬화하려면 클래스가 java.io.Serializable 인터페이스구현해야합니다 . Serializable은 마커 인터페이스이며이를 구현하는 클래스에 serializable 동작을 추가해야 함을 컴파일러에 알리는 데 사용됩니다. 여기서 JVM (Java Virtual Machine)은 자동 직렬화를 담당합니다.

    일시적 키워드 : java.io.Serializable interface

    객체를 직렬화하는 동안 객체의 특정 데이터 멤버를 직렬화하지 않으려면 과도 수정자를 사용할 수 있습니다. transient 키워드는 해당 데이터 멤버가 직렬화되지 않도록합니다.

    • 일시적 또는 정적으로 선언 된 필드는 직렬화 프로세스에서 무시됩니다.

    일시적휘발성

    +--------------+--------+-------------------------------------+
    |  Flag Name   |  Value | Interpretation                      |
    +--------------+--------+-------------------------------------+
    | ACC_VOLATILE | 0x0040 | Declared volatile; cannot be cached.|
    +--------------+--------+-------------------------------------+
    |ACC_TRANSIENT | 0x0080 | Declared transient; not written or  |
    |              |        | read by a persistent object manager.|
    +--------------+--------+-------------------------------------+
    
    class Employee implements Serializable {
        private static final long serialVersionUID = 2L;
        static int id;
    
        int eno; 
        String name;
        transient String password; // Using transient keyword means its not going to be Serialized.
    }
    
  • Externalizable 인터페이스를 구현하면 객체의 직렬화 된 양식의 내용과 형식을 완전히 제어 할 수 있습니다. Externalizable 인터페이스의 메소드 인 writeExternal 및 readExternal은 오브젝트 상태를 저장하고 복원하기 위해 호출됩니다. 클래스에 의해 구현되면 ObjectOutput 및 ObjectInput의 모든 메소드를 사용하여 자체 상태를 읽고 읽을 수 있습니다. 발생하는 모든 버전 관리를 처리하는 것은 객체의 책임입니다.

    class Emp implements Externalizable {
        int eno; 
        String name;
        transient String password; // No use of transient, we need to take care of write and read.
    
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeInt(eno);
            out.writeUTF(name);
            //out.writeUTF(password);
        }
        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            this.eno = in.readInt();
            this.name = in.readUTF();
            //this.password = in.readUTF(); // java.io.EOFException
        }
    }
    
  • java.io.Serializable 또는 java.io.Externalizable 인터페이스를 지원하는 오브젝트 만이 written to/read from stream 일 수 있습니다 . 각 직렬화 가능 객체의 클래스는 클래스 이름 및 클래스의 서명, 객체 필드 및 배열의 ​​값, 초기 객체에서 참조 된 다른 객체의 폐쇄를 포함하여 인코딩됩니다.

파일의 직렬화 가능 예

public class SerializationDemo {
    static String fileName = "D:/serializable_file.ser";

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        Employee emp = new Employee( );
        Employee.id = 1; // Can not Serialize Class data.
        emp.eno = 77;
        emp.name = "Yash";
        emp.password = "confidential";
        objects_WriteRead(emp, fileName);

        Emp e = new Emp( );
        e.eno = 77;
        e.name = "Yash";
        e.password = "confidential";
        objects_WriteRead_External(e, fileName);

        /*String stubHost = "127.0.0.1";
        Integer anyFreePort = 7777;
        socketRead(anyFreePort); //Thread1
        socketWrite(emp, stubHost, anyFreePort); //Thread2*/

    }
    public static void objects_WriteRead( Employee obj, String serFilename ) throws IOException{
        FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );
        objectOut.writeObject( obj );
        objectOut.close();
        fos.close();

        System.out.println("Data Stored in to a file");

        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

            Employee emp = (Employee) readObject;
            System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void objects_WriteRead_External( Emp 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.
            Emp emp = new Emp();

            FileInputStream fis = new FileInputStream(new File( serFilename ));
            ObjectInputStream ois = new ObjectInputStream( fis );

            emp.readExternal(ois);

            System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

네트워크를 통한 직렬화 가능 예

동일한 컴퓨터의 다른 프로세스 또는 네트워크를 통해 연결된 여러 컴퓨터에서 서로 다른 주소 공간에 객체 상태를 배포 하지만 데이터를 공유하고 메서드를 호출하여 함께 작동합니다.

/**
 * Creates a stream socket and connects it to the specified port number on the named host. 
 */
public static void socketWrite(Employee objectToSend, String stubHost, Integer anyFreePort) {
    try { // CLIENT - Stub[marshalling]
        Socket client = new Socket(stubHost, anyFreePort);
        ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
        out.writeObject(objectToSend);
        out.flush();
        client.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
// Creates a server socket, bound to the specified port. 
public static void socketRead(  Integer anyFreePort ) {
    try { // SERVER - Stub[unmarshalling ]
        ServerSocket serverSocket = new ServerSocket( anyFreePort );
        System.out.println("Server serves on port and waiting for a client to communicate");
            /*System.in.read();
            System.in.read();*/

        Socket socket = serverSocket.accept();
        System.out.println("Client request to communicate on port server accepts it.");

        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        Employee objectReceived = (Employee) in.readObject();
        System.out.println("Server Obj : "+ objectReceived.name );

        socket.close();
        serverSocket.close();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
}

@보다


| * | 클래스 직렬화 : 객체를 바이트로 변환하고 바이트를 객체로 다시 변환 (직렬화).

class NamCls implements Serializable
{
    int NumVar;
    String NamVar;
}

| => 객체 직렬화는 객체 상태를 바이트 단위로 변환하는 프로세스입니다.

  • |-> 오브젝트가 JVM 수명을 초과하여 존재하도록하려는 경우 구현하십시오.
  • |-> 직렬화 된 오브젝트는 데이터베이스에 저장 될 수 있습니다.
  • |-> 직렬화 가능 오브젝트는 사람이 읽고 이해할 수 없으므로 보안을 확보 할 수 있습니다.

| => Object-Deserialization은 오브젝트의 상태를 가져 와서 오브젝트 (java.lang.Object)에 저장하는 프로세스입니다.

  • |-> 상태를 저장하기 전에 serialVersionUID 양식 입력 파일 / 네트워크 및 .class 파일 serialVersionUID가 동일한 지 확인합니다.
    & nbsp & nbspjava.io.InvalidClassException을 발생시키지 않는 경우

| => Java 오브젝트는 해당 클래스 또는 수퍼 클래스 인 경우에만 직렬화 가능합니다.

  • java.io.Serializable 인터페이스 또는
  • 서브 인터페이스, java.io.Externalizable

| => 클래스의 정적 필드는 직렬화 할 수 없습니다.

class NamCls implements Serializable
{
    int NumVar;
    static String NamVar = "I won't be serializable";;
}

| => 클래스의 변수를 직렬화하지 않으려면 transient 키워드를 사용하십시오.

class NamCls implements Serializable
{
    int NumVar;
    transient String NamVar;
}

| => 클래스가 직렬화 가능을 구현하면 모든 서브 클래스도 직렬화 가능합니다.

| => 클래스에 다른 클래스의 참조가있는 경우 모든 참조는 직렬화 가능해야합니다. 그렇지 않으면 직렬화 프로세스가 수행되지 않습니다. 이러한 경우
런타임에 NotSerializableException이 발생합니다.

참고 URL : https://stackoverflow.com/questions/447898/what-is-object-serialization



반응형