ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JAVA - 직렬화, 역직렬화
    개발 2023. 2. 24. 15:13

    직렬화, 역직렬화

     

    자바의 직렬화는 객체를 바이트의 연속으로 변환시키는 기술이다. 역직렬화는 반대로 바이트의 연속을 오브젝트로 전환해주는 기술이다. 직렬화된 객체가 파일에 기록되면 역직렬화를 통해 파일에서 읽어온 데이터를 메모리에서 객체로 쓸 수 있다.

     

    이렇게 인터뷰용 답변만 준비하지말고 직접 코딩해서 체험해보는게 좋다. Person이라는 클래스를 직렬화해서 file.ser이라는 파일에 바이트코드를 써보자.

     

    data class Person(val name: String, val age: Int) : Serializable
    
    try {
        val person = Person(name = "ryan", age = 30)
        val fileOut = FileOutputStream("file.ser")
        val objOut = ObjectOutputStream(fileOut)
    
        objOut.writeObject(person)
        objOut.close()
        fileOut.close()
    } catch (e: IOException) {
        e.printStackTrace()
    }
    

     

    그러면 file.ser 이라는 파일이 생성된다. vim 에디터를 통해서 열어보면 Person의 정보가 바이트로 입력되어있다.

     

     

    이제는 역직렬화를 통해서 바이트를 오브젝트로 바꿀 차례다. 파일에서 바이트코드를 읽어오고 역직렬화를 통해 Person 객체로 선언했다. 그 결과 입력했던 값과 동일한 객체를 얻어낼 수 있었다.

     

    try {
        val fileIn = FileInputStream("file.ser")
        val objIn = ObjectInputStream(fileIn)
        val person = objIn.readObject() as Person
    
        println("person: ${person.name} ${person.age}")
    } catch (e: ClassNotFoundException) {
        e.printStackTrace()
    }
    --------------------------------------------------------
    person: ryan 30
    

     

    serialVersionUID

     

    그런데 파일에 입력했을때와 읽어올 때 클래스가 달라질 수 있다. 이미 파일에 값을 써둔 상태에서 Person 클래스에 gender라는 속성을 추가했다고 해보자. 그러면 읽어올 때 어떻게 읽어오게 될까?

     

    data class Person(val name: String, val age: Int, val gender: Int) : Serializable
    
    try {
        val fileIn = FileInputStream("file.ser")
        val objIn = ObjectInputStream(fileIn)
        val person = objIn.readObject() as Person
    
        println("person: ${person.name} ${person.age} ${person.gender}")
    } catch (e: ClassNotFoundException) {
        e.printStackTrace()
    }
    --------------------------------------------------------
    person: ryan 30 0
    

     

    Exception은 발생하지 않고 값을 기록하지 않았던 gender는 0으로 세팅된다. 디폴트 값을 넣어주는 방식을 선호할 수 있지만 경우에 따라선 유효하지 않은 값이기 때문에 에러를 출력하는 것이 적절할 수도 있다.

     

    자바에선 serialVersionUID 변수 값을 이용해 클래스별로 바이트 연속에 직렬화 버전 값을 넣어줄 수 있다. 역직렬화 할때는 대상인 클래스의 serialVersionUID 값이 직렬화때 사용한 값과 동일해야 정상적으로 읽어오게 된다.

     

    테스트를 해보자. 직렬화 할때는 serialVersionUID 값을 1로 주고 파일에 저장했다.

     

    data class Person(val name: String, val age: Int, val gender: Int) : Serializable {
        companion object {
            private const val serialVersionUID: Long = 1L
        }
    }
    
    try {
        val person = Person(name = "ryan", age = 30, gender = 1)
        val fileOut = FileOutputStream("file.ser")
        val objOut = ObjectOutputStream(fileOut)
    
        objOut.writeObject(person)
        objOut.close()
        fileOut.close()
    } catch (e: IOException) {
        e.printStackTrace()
    }
    

     

    그리고 역직렬화 할때는 serialVersionUID를 2로 바꿨다.

     

    data class Person(val name: String, val age: Int, val gender: Int) : Serializable {
        companion object {
            private const val serialVersionUID: Long = 2L
        }
    }
    

     

    그 결과 serial version 이 맞지 않는다는 에러를 띄운다. 버전 정보를 활용해서 직렬화를 관리하면 될 것 같다.

     

    '개발' 카테고리의 다른 글

    Java - synchronized, wait, notify  (0) 2023.02.28
    자바 - Garbage Collector  (0) 2023.02.24
    Flask SQLAlchemy vs SQLAlchemy  (0) 2023.02.14
    Python - namedtuple  (0) 2023.02.14
    Python - 제너레이터  (0) 2023.02.14

    댓글

Designed by Tistory.