-
SerializableJava 2020. 2. 7. 09:35반응형
Serializable
java.io 패키지의 Serializable Interface
선언된 변수나 메서드가 없음
클래스가 파일에 읽거나 쓸 수 있도록 하거나, 다른 서버로 보내거나 받을 수 있도록 하려면 해당 인터페이스를 구현(implements)해야 함 - 구현시 JVM에서 해당 객체를 저장하거나 다른 서버로 전송할 수 있도록 해줌
serialVersionUID
Serializable 인터페이스를 구현한 후, serialVersionUID 값을 지정해주는 것을 권장
별도로 지정하지 않으면, 컴파일시 자동 생성 됨
static final long serialVersionUID = 1L;
뒤에 지정하는 값 : 해당 객체의 버전을 명시하는 데 사용됨
: 해당 객체가 같은지 다른지를 확인할 수 있도록 관리하는 값
단, 같은 UID일지라도 변수의 개수나 타입 등이 다르면 다른 클래스로 인식함 유의
ObjectOutputStream & ObjectInputStream
ObjectOutputStream : 자바에서 해당 클래스를 사용시 객체를 저장할 수 있음
ObjectInputStream : 자바에서 해당 클래스를 사용하면 저장해 놓은 객체를 읽을 수 있음
객체 저장
import java.io.FileOutputStream; import java.io.ObjectOutputStream; import static java.io.File.separator; public class ManageObject { public static void main(String[] args) { ManageObject manager = new ManageObject(); String fullPath = "/Users/hs" + separator + "chicken.obj"; SerialDTO dto = new SerialDTO("ABChicken", 1, true, 100); manager.saveObject(fullPath, dto); } public void saveObject(String fullPath, SerialDTO dto) { FileOutputStream fos = null; ObjectOutputStream oos = null; try { // 파일 객체 생성 fos = new FileOutputStream(fullPath); // ObjectOutputStream 객체, 생성시 파일객체를 넘김 > 파일에 저장됨 oos = new ObjectOutputStream(fos); // 매개 변수로 넘어온 객체 저장 oos.writeObject(dto); System.out.println("Write Success"); } catch (Exception e) { e.printStackTrace(); } finally { if (oos != null) { try { oos.close(); } catch (Exception e) { e.printStackTrace(); } } if (fos!=null) { try { fos.close(); } catch (Exception e) { e.printStackTrace(); } } } } }
import java.io.Serializable; public class SerialDTO implements Serializable { private String chickenName; private int chickenOrder; private boolean bestChicken; private long soldPerDay; public SerialDTO(String chickenName, int chickenOrder, boolean bestChicken, long soldPerDay) { super(); this.chickenName = chickenName; this.chickenOrder = chickenOrder; this.bestChicken = bestChicken; this.soldPerDay = soldPerDay; } @Override public String toString() { return "SerialDTO [chickenName = " + chickenName + ", chickenOrder = " + chickenOrder + ", bestChicken = " + bestChicken + ", soldPerDay = " + soldPerDay + "]"; } } // Serializable 구현하지 않을 경우 java.io.NotSerializableException: SerialDTO at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) at ManageObject.saveObject(ManageObject.java:23) at ManageObject.main(ManageObject.java:11) // 구현한 경우 - 파일에 들어감 (바이너리 형식..) $ cat /Users/hs/chicken.obj ??sr SerialDTOJ,?>?Eo?Z bestChickenI chickenOrderJ soldPerDayL chickenNametLjava/lang/String;xpdt ABChicken
객체 읽기
import java.io.*; import static java.io.File.separator; public class ManageObject { public static void main(String[] args) { ManageObject manager = new ManageObject(); String fullPath = "/Users/hs" + separator + "chicken.obj"; manager.loadObject(fullPath); } public void loadObject(String fullPath) { FileInputStream fis = null; ObjectInputStream ois = null; try { fis = new FileInputStream(fullPath); ois = new ObjectInputStream(fis); Object obj = ois.readObject(); SerialDTO dto = (SerialDTO) obj; System.out.println(dto); } catch (Exception e) { e.printStackTrace(); } finally { if (ois != null) { try { ois.close(); } catch (Exception e) { e.printStackTrace(); } } if (fis != null) { try { fis.close(); } catch (Exception e) { e.printStackTrace(); } } } } } // 내용 확인 SerialDTO [chickenName = ABChicken, chickenOrder = 1, bestChicken = true, soldPerDay = 100] BUILD SUCCESSFUL in 0s
Serializable 객체의 형태가 변경되면
컴파일시 serialVersionUID가 재생성됨
즉, Serializable을 구현한 클래스에 클래스 변수를 추가한다면, serialVersionUID가 변경되므로 읽을 수 없게됨
// SerialDTO에 클래스 변수가 추가된다면 - 객체읽을경우 // private String chickenType = "A"; java.io.InvalidClassException: SerialDTO; local class incompatible: stream classdesc serialVersionUID = 5344876925460770704, local class serialVersionUID = -8689217447952664982 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1885) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431) at ManageObject.loadObject(ManageObject.java:18) at ManageObject.main(ManageObject.java:9)
그럴경우 serialVersionUID를 명시해주기
static final long serialVersionUID = 1L;
serialVersionUID를 지정해놓은 상태에서 저장되어 있는 객체와 읽는 객체가 다르면?
SerialDTO [chickenName=ABChicken, chickenOrder=2, bestChicken=true, soldPerDay=200, ChickenTypes=null]
-
변수의 이름이 바뀌거나 추가되는 등 하면, 객체에서 찾을 수 없으면 null로 처리
-
예외는 발생하지 않음
-
Serializable한 객체의 내용이 바뀌었는데도 예외가 발생하지 않으면 데이터가 꼬일 수 있음 = 권장하지 않음
-
데이터가 변경되면 serialVersionUID를 변경하는 습관을 가질 것 > 자동으로 해주는 IDE도 많음
transient 예약어
보안상 중요한 변수나 꼭 저장할 필요가 없는 변수에 대해 사용하는 예약어
객체를 저장하거나 타 JVM으로 보낼 때, transient라는 예약어를 사용하여 선언한 변수는 Serializable 대상에서 제외됨 (아예 무시 됨)
해당 객체를 생성한 JVM에서 사용할 때는 문제 없음
패스워드 등에서 사용
반응형'Java' 카테고리의 다른 글
Enum(열거형) (0) 2020.02.08 서버 통신 - Socket / UDP (0) 2020.02.07 Java NIO (0) 2020.02.06 JAVA I/O (0) 2020.02.06 Thread 관련 - Object, ThreadGroup, ThreadLocal, volatile (0) 2020.01.16 -