직렬화 가능이란 무엇입니까?


136

클래스가 SerializableJava 로 존재한다는 것은 정확히 무엇을 의미 합니까? 또는 일반적으로 그 문제에 대해 ...


10
@skaffman이 수업에 대해 말하는 내용은 다음과 같습니다 Serializable. Serializability of a class is enabled by the class implementing the java.io.Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized. All subtypes of a serializable class are themselves serializable. The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.
Ritwik Bose

32
직렬화 및 직렬화 해제가 무엇을 의미하는지 이미 알고 있다면 훌륭한 설명입니다. (칭찬은 아님) 그러한 정의는 문제를 기술적으로 한 번만 더 잘 이해하는 데 도움이되고 한 번만 이해하면됩니다.
Xonatron

답변:


132

직렬화 는 예를 들어 디스크에 저장하기 위해 메모리에서 일련의 비트로 객체를 유지합니다. 역 직렬화는 반대입니다. 디스크에서 데이터를 읽어 객체를 수화 / 생성합니다.

질문의 맥락에서 클래스에서 구현되는 경우이 클래스는 다른 직렬 변환기에 의해 자동으로 직렬화 및 직렬화 해제 될 수있는 인터페이스입니다.


2
또한 명시 적으로 표시되지 않은 모든 필드도 직렬화됩니다. 즉, 루트 개체를 직렬화하는 것만으로 복잡한 데이터 구조를 쉽게 저장할 수 있습니다.
Thorbjørn Ravn Andersen 님이 08:07

1
"객체"에 대해 이야기 할 때 클래스에 의해 인스턴스화 된 객체 또는 어셈블리, 파일 등과 같은 "소프트웨어 객체"를 의미합니까? 후자가 프로그램과 환경간에 데이터를 전송하는 표준화 된 방법일까요?
Sunburst275

1
@ Sunburst275-이 경우 메모리에있는 클래스의 메모리에 대한 표현입니다. 즉, 클래스의 인스턴스입니다. 단순히 그대로 전송됩니다).
오디드

44

대부분의 사용자가 이미 답변을했지만 아이디어를 설명하기 위해 필요한 사람들을위한 예를 추가하고 싶습니다.

다음과 같은 클래스 사람이 있다고 가정 해 봅시다.

public class Person implements java.io.Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public String firstName;
    public String lastName;
    public int age;
    public String address;

    public void play() {
        System.out.println(String.format(
                "If I win, send me the trophy to this address: %s", address));
    }
    @Override
    public String toString() {
        return String.format(".....Person......\nFirst Name = %s\nLast Name = %s", firstName, lastName);
    }
}

그런 다음 다음과 같은 객체를 만듭니다.

Person william = new Person();
        william.firstName = "William";
        william.lastName = "Kinaan";
        william.age = 26;
        william.address = "Lisbon, Portugal";

해당 개체를 여러 스트림으로 직렬화 할 수 있습니다. 나는 두 가지 흐름으로 그렇게 할 것입니다.

표준 출력으로 직렬화 :

public static void serializeToStandardOutput(Person person)
            throws IOException {
        OutputStream outStream = System.out;
        ObjectOutputStream stdObjectOut = new ObjectOutputStream(outStream);
        stdObjectOut.writeObject(person);
        stdObjectOut.close();
        outStream.close();
    }

파일로 직렬화 :

public static void serializeToFile(Person person) throws IOException {
        OutputStream outStream = new FileOutputStream("person.ser");
        ObjectOutputStream fileObjectOut = new ObjectOutputStream(outStream);
        fileObjectOut.writeObject(person);
        fileObjectOut.close();
        outStream.close();
    }

그때:

파일에서 역 직렬화 :

public static void deserializeFromFile() throws IOException,
            ClassNotFoundException {
        InputStream inStream = new FileInputStream("person.ser");
        ObjectInputStream fileObjectIn = new ObjectInputStream(inStream);
        Person person = (Person) fileObjectIn.readObject();
        System.out.println(person);
        fileObjectIn.close();
        inStream.close();
    }

감사합니다. 나는 지금 그것을 얻었다 생각합니다.
Sunburst275

40

즉, 클래스의 인스턴스를 바이트 스트림으로 변환 한 다음 (예 : 파일로 저장) 다시 클래스로 변환 할 수 있습니다. 이 리로딩은 프로그램의 다른 인스턴스 또는 다른 머신에서도 발생할 수 있습니다. 직렬화 (어떤 언어로든)는 특히 모든 직렬화 가능한 개체 내의 다른 개체에 대한 참조가있는 경우 모든 종류의 문제를 포함합니다.


15

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

직렬화 :

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

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

현대 건축에서는 항상 객체 상태를 저장 한 다음 검색해야합니다. 예를 들어, 최대 절전 모드에서 객체를 저장하려면 클래스를 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 선언은 가능한 경우 전용 수정자를 사용하는 것이 좋습니다.

만약 당신이 우리가 사용한 다른 키워드가 transient 인 것을 눈치 채 셨다면 .

필드를 직렬화 할 수없는 경우 일시적으로 표시해야합니다. 여기서 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) 이 작성되지 않았습니다으로가.


2
이 자세한 설명에 감사드립니다.
Promise Preston

이것은 좋은 설명입니다! 감사합니다! 그러나 솔직히 말하면이 항목은 블로그에있는 항목보다 훨씬 깔끔해 보입니다. 어쨌든, 이것은 많은 도움이되었습니다!
Sunburst275

11

직렬화에는 객체의 현재 상태를 스트림에 저장하고 해당 스트림에서 동등한 객체를 복원하는 작업이 포함됩니다. 스트림은 객체의 컨테이너로 기능합니다


1
이 정의가 더 정확 해 보입니다. 감사합니다.
Promise Preston

6

직렬화 가능은 인터페이스처럼 호출되지만 런타임시 직렬화 서브 시스템에 대한 플래그와 유사합니다. 이 개체를 저장할 수 있다고 말합니다. 직렬화 가능한 객체 및 휘발성으로 표시된 객체를 제외한 모든 객체 인스턴스 변수가 저장됩니다.

외부 설정을 유지하지 않고도 응용 프로그램에서 색상을 옵션으로 변경할 수 있다고 상상할 때마다 색상을 실행할 때마다 색상을 변경해야합니다.


5
'컴파일러의 플래그'가 아닙니다. 런타임시 직렬화 서브 시스템에 대한 플래그입니다.
Lorne의 후작

1
@EJP-감사합니다, 몰랐습니다
AphexMunky

사실, 당신이 그것이 사실인지 모를 때 왜 그것을 쓰십니까? 또한 '일시적'을 생략했습니다. 모든 나쁜 대답, 미안합니다.
Lorne의 후작

19
내가 쓰지 않았다면 정정되지 않았고 더 나빠질 것입니다. 다른 모든 답변도 일시적으로 중단되었습니다. 당신은 답을 쓰지 않았고 단지 다른 사람들을 트롤링하고 있습니다.
AphexMunky

4

직렬화는 객체와 데이터를 파일에 저장하거나 쓰는 기술입니다. ObjectOutputStreamFileOutputStream클래스 를 사용 합니다. 이 클래스에는 객체를 유지하기위한 특정 메소드가 있습니다. 처럼writeObject();

수치와 명확한 explantaion. 자세한 내용은 여기를 참조하십시오


2

다른 관점에서 제시합니다. 직렬화는 '마커 인터페이스'라는 일종의 인터페이스입니다. 마커 인터페이스는 메소드 선언을 포함하지 않고 인터페이스를 일부 속성을 갖는 것으로 구현하는 클래스를 지정 (또는 "표시")하는 인터페이스입니다. 다형성을 이해한다면 이것은 매우 의미가 있습니다. Serializable 마커 인터페이스의 경우 인수가 인터페이스를 구현하지 않으면 ObjectOutputStream.write (Object) 메소드가 실패합니다. 이것은 자바에서 잠재적 인 실수이며 ObjectOutputStream.write (Serializable) 일 수 있습니다.

권장 사항 : Joshua Bloch의 Effective Java 에서 항목 37을 읽고 자세히 알아보십시오.


2

직렬화 : 파일 / 네트워크 또는 다른 곳에 객체 상태 쓰기. (지원되는 Java 오브젝트 지원 양식 또는 파일 지원 양식 또는 네트워크 지원 양식)

역 직렬화 : 파일 / 네트워크 또는 어디서나 객체 상태를 읽습니다. (평균 파일 / 네트워크 지원 양식에서 Java 오브젝트 지원 양식으로)


1

다른 답변에 추가하고 일반 성과 관련하여 추가하십시오. 직렬화는 때때로 Objective-C에서 아카이브로 알려져 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.