-
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