개발자 HOON
πŸ› HOON DEVLog
개발자 HOON
전체 방문자
였늘
μ–΄μ œ
  • 😎 전체 μΉ΄ν…Œκ³ λ¦¬ (137)
    • πŸ“ μ‹ μž… 인터뷰 μ€€λΉ„ (7)
    • πŸ¦” μ·¨μ—…μ€€λΉ„ 기둝 (7)
    • β˜• μžλ°” : JAVA (5)
    • 🐍 μ½”λ”©ν…ŒμŠ€νŠΈ λŒ€λΉ„ : PS (80)
    • 🌱 λ°±μ—”λ“œ : Backend (13)
    • πŸ§ͺ 컴퓨터과학 : CS (11)
    • πŸ—‚ λ°μ΄ν„°λ² μ΄μŠ€ : DB (1)
    • πŸƒ‍♂️ DEVLOG (8)
    • βš™οΈ Trouble Shooting (5)

λΈ”λ‘œκ·Έ 메뉴

  • ν™ˆ
  • GitHub
  • Resume

곡지사항

인기 κΈ€

졜근 κΈ€

ν‹°μŠ€ν† λ¦¬

hELLO Β· Designed By μ •μƒμš°.
개발자 HOON

πŸ› HOON DEVLog

[Java] μžλ°” 직렬화 (Serialization)
β˜• μžλ°” : JAVA

[Java] μžλ°” 직렬화 (Serialization)

2023. 1. 6. 15:43

 

πŸ€” 1. μžλ°” μ§λ ¬ν™”λž€?

 

μžλ°” 직렬화(Java Serialization)은, 객체의 μƒνƒœλ₯Ό μ˜μ†ν™” ν•˜λŠ” λ§€μ»€λ‹ˆμ¦˜μž…λ‹ˆλ‹€.

μ˜μ†ν™”λŠ”, 영ꡬ적으둜 속성을 μ €μž₯ν•˜λŠ” 것을 μ˜λ―Έν•˜λ―€λ‘œ, μ‰½κ²Œ ν’€μ–΄μ„œ μ„€λͺ…ν•˜λ©΄ 객체λ₯Ό λ‹€λ₯Έ ν™˜κ²½μ— μ €μž₯ν–ˆλ‹€κ°€ λ‚˜μ€‘μ— μž¬κ΅¬μ„±ν•  수 μžˆλŠ” 것이 κ³§ μžλ°” μ§λ ¬ν™”μ˜ μ˜λ―Έμž…λ‹ˆλ‹€.

 

λ‹¨μˆœνžˆ μ €μž₯이라고 ν‘œν˜„ν–ˆμ§€λ§Œ, 일반적으둜 μš°λ¦¬κ°€ μƒκ°ν•˜λŠ” λ°μ΄ν„°λ² μ΄μŠ€ μ €μž₯, 파일의 ν˜•νƒœλ‘œ μ €μž₯도 해당이 λ˜μ§€λ§Œ, λ©”λͺ¨λ¦¬ 및 μΊμ‹œμ— μ €μž₯ν•˜λŠ” 것 μ—­μ‹œ 직렬화라고 ν‘œν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 

 

μžλ°” 직렬화λ₯Ό 톡해 객체λ₯Ό μ˜¨μ „νžˆ λ‹€λ₯Έ 곳에 μ €μž₯ν•˜κ³ , λ‹€μ‹œ μ˜¨μ „ν•œ 객체둜 μž¬κ΅¬μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό 톡해 μ‰½κ²Œ λΆ„μ‚° 객체 생성이 κ°€λŠ₯ν•΄μ‘ŒμŠ΅λ‹ˆλ‹€. μžλ°” μ§λ ¬ν™”μ—μ„œ μ €μž₯ν•˜λŠ” 방식은, 객체λ₯Ό λ°”μ΄νŠΈ 슀트림의 ν˜•νƒœλ‘œ λ§Œλ“€μ–΄ 이λ₯Ό μ €μž₯ν•©λ‹ˆλ‹€.

 

 

πŸ€” 2. μžλ°” μ§λ ¬ν™”λŠ” μ–Έμ œ μ“°λ‚˜μš”?

 

객체의 μƒνƒœλ₯Ό μ˜μ†(μ–΄λ”˜κ°€μ— 영ꡬ적으둜 μ €μž₯)ν•΄μ•Ό ν•  λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.

객체둜 μž¬κ΅¬μ„±ν•  수 μžˆλ‹€λŠ” μ μ—μ„œ, λ‹€λ₯Έ VMμ—κ²Œ 객체의 정보λ₯Ό 전달해야 ν•  λ•Œ μ‚¬μš©ν•˜κΈ°λ„ ν•©λ‹ˆλ‹€. (Remote Method Invocation ν˜Ήμ€ Socket을 μ‚¬μš©ν•΄μ„œ.)

 

μ‚¬μš©ν•˜λŠ” 방법은 λ‹¨μˆœν•©λ‹ˆλ‹€.

package java.io;

public interface Serializable {}

public class MyObject implemets Serializable{
	public int value;
    
    public MyObject(final int value){
   		this.value = value;
    }
}

 

μœ„μ˜ μ½”λ“œμ—μ„œ λ³Ό 수 μžˆλ“―μ΄ Serializable μΈν„°νŽ˜μ΄μŠ€λŠ” 곡개 APIκ°€ μ—†λŠ” λ‹¨μˆœν•œ 마컀 μΈν„°νŽ˜μ΄μŠ€μž…λ‹ˆλ‹€.

ν•˜μ§€λ§Œ 이 Serializable μΈν„°νŽ˜μ΄μŠ€λ₯Ό implements ν•΄μ£ΌλŠ” κ²ƒλ§ŒμœΌλ‘œλ„ ν•΄λ‹Ή κ°μ²΄λŠ” 직렬화 κ°€λŠ₯ν•œ 객체둜 λ³€μ‹ ν•˜κ²Œ λ©λ‹ˆλ‹€!

λ§Œμ•½ Serializable μΈν„°νŽ˜μ΄μŠ€λ₯Ό implementsν•˜μ§€ μ•ŠλŠ” 객체λ₯Ό 직렬화 ν•˜λ €κ³  ν•œλ‹€λ©΄, NotSerializableException이 λ°œλ°œν•˜κ²Œ λ˜λ―€λ‘œ μ£Όμ˜κ°€ ν•„μš”ν•©λ‹ˆλ‹€!

 

byte[] serailizedObject;

try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
	ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {
    	MyObject myObject = new MyObject(1);
        objectOutputStream.writeObject(myObject);
        serializedObject = byteArrayOutputStream.toByteArray();
    }

직렬화λ₯Ό ν•˜λŠ” 것은 java.io.ObjectOutputStream을 μ‚¬μš©ν•©λ‹ˆλ‹€. try-with-resource 문을 μ‚¬μš©ν•΄ byteArrayOutputStreamκ³Ό ObjectOutputStream을 μƒμ„±ν•œ λ’€, writeObject λ©”μ†Œλ“œμ™€ toByteArray λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•΄ 직렬화λ₯Ό ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

λ°˜λŒ€λ‘œ μ—­μ§λ ¬ν™”λŠ” java.io.ObjectInputStreamλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. 

μ—­μ§λ ¬ν™”λŠ”, λ°”μ΄νŠΈ 슀트림으둜 μ €μž₯된 데이터λ₯Ό 객체둜 μž¬κ΅¬μ„±ν•˜λŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€.

byte[] serializedObject = getSerializedObject();

try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(serializedObject);
	ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)){
    	MyObject myObject = (MyObject) objectInputStream.readObject();
    }

그리고 ObjectInputStream의 readObject λ©”μ†Œλ“œμ™€ νƒ€μž… μΊμŠ€νŒ…μ„ 톡해 역직렬화λ₯Ό μ§„ν–‰ν•΄ κ²°κ΅­, 객체λ₯Ό μ˜¨μ „νžˆ μž¬κ΅¬μ„±ν•  수 있게 λ©λ‹ˆλ‹€.

 

https://www.youtube.com/watch?v=3iypR-1Glm0

전체적인 ν”Œλ‘œμš°λŠ” μœ„μ™€ κ°™μŠ΅λ‹ˆλ‹€.

 

 

πŸ€” 3. SerialVersionUID의 μš©λ„λŠ” λ¬΄μ—‡μΌκΉŒ?

 

Serialization을 implementsν•˜λŠ” 객체듀은, 클래슀의 버전 관리λ₯Ό μœ„ν•΄ serialVersionUID λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜κ²Œ λ©λ‹ˆλ‹€.

이 serialVersionUID λ³€μˆ˜λŠ” κ°œλ°œμžκ°€ 직접 μ •μ˜ν•˜μ§€ μ•ŠμœΌλ©΄, μ»΄νŒŒμΌλŸ¬κ°€ μ•Œμ•„μ„œ λΆ€μ—¬ν•˜κ²Œ λ©λ‹ˆλ‹€.

이 serialVersionUIDλŠ” 직렬화 ν•  λ•Œ 같이 μ €μž₯되게 되고, 역직렬화λ₯Ό ν•  λ•Œμ—λŠ” κ·Έ 값을 μ²΄ν¬ν•˜λŠ” μš©λ„λ‘œ μ‚¬μš©ν•˜κ²Œ λ©λ‹ˆλ‹€.

 

예λ₯Ό λ“€μ–΄ serialVersionUID 값을 1L둜 μ„€μ •ν•œ ν›„ 직렬화λ₯Ό ν–ˆμŠ΅λ‹ˆλ‹€. κ·Έ 이후, ν•΄λ‹Ή 클래슀의 serialVersionUID 값을 2L둜 λ³€κ²½ν•œ λ’€, 역직렬화λ₯Ό μ‹œλ„ν•˜λ©΄ invalidClassException이 λ°œμƒν•˜κ²Œ λ©λ‹ˆλ‹€. 즉 버전 관리λ₯Ό κ°€λŠ₯μΌ€ ν•˜λŠ” 것이죠.

 

SerialVersionUIDλŠ” κ°œλ°œμžκ°€ 직접 μ„€μ •ν•˜λŠ” 것을 ꢌμž₯ν•©λ‹ˆλ‹€. κ·Έ μ΄μœ λŠ” 컴파일러의 μž„μ˜ 뢀여에 μžˆμŠ΅λ‹ˆλ‹€. JVM의 λ‚΄λΆ€ μ•Œκ³ λ¦¬μ¦˜μ— μ˜ν•΄ ν•΄λ‹Ή 값이 κ²°μ •λ˜κ²Œ λ˜λŠ”λ°, λ¬Έμ œλŠ” μ–΄λ–€ JVM을 μ‚¬μš©ν•˜λŠ”μ§€μ— λ”°λΌμ„œ 이 값이 λ‹¬λΌμ§€κ²Œ λ©λ‹ˆλ‹€.

 

λ”°λΌμ„œ Clientκ°€ Windows, μ„œλ²„κ°€ Linux인 경우 μ„œλ‘œ λ‹€λ₯Έ JVM을 μ‚¬μš©ν•˜κ²Œ λ˜μ–΄ 이 값이 달라져 역직렬화λ₯Ό μ§„ν–‰ν•  λ•Œ Exception이 λ°œμƒν•  μ—¬μ§€κ°€ μžˆμŠ΅λ‹ˆλ‹€.

 

 

 

πŸ€” 4. μ™œ μžλ°” μ§λ ¬ν™”λŠ” 잘 μ•ˆ μ“°κ²Œ λ˜λŠ” 걸까?

 

이 μ§λ ¬ν™”λΌλŠ” κ°œλ…μ€ 많이 듀어보긴 ν–ˆμœΌλ‚˜ 싀무 κ²½ν—˜μ΄ λΆ€μ‘±ν•œ λ‚΄κ²ŒλŠ” 잘 쓰이지 μ•ŠλŠ”λ‹€λŠ” λŠλ‚Œμ„ λ°›μ•˜μŠ΅λ‹ˆλ‹€.

직렬화λ₯Ό κΈ°ν”Όν•˜λŠ” μ΄μœ λŠ” λ³΄μ•ˆ 문제, μœ μ§€ λ³΄μˆ˜μ„±, ν…ŒμŠ€νŠΈ λ“±μ—μ„œ λ³΅μž‘ν•¨μ΄ μžˆμ–΄μ„œ κ·Έλ ‡λ‹€κ³  ν•©λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄ ν™•μΈν•΄λ΄…μ‹œλ‹€.

 

1) λ³΄μ•ˆ 문제

μ§λ ¬ν™”λœ λ°”μ΄νŠΈ μŠ€νŠΈλ¦Όμ„ 역직렬화 ν•  λ•Œμ—λŠ” readObject λ©”μ†Œλ“œκ°€ 호좜되게 λ©λ‹ˆλ‹€. 근데 이것 μžμ²΄κ°€ ν•˜λ‚˜μ˜ μƒμ„±μžμ™€ λ‹€λ₯Όκ²Œ μ—†μŠ΅λ‹ˆλ‹€. 즉, 보이지 μ•ŠλŠ” μƒμ„±μžμ˜ λ¬Έμ œκ°€ μƒκΈ°κ²Œ λ©λ‹ˆλ‹€.

 

이게 μ™œ λ¬Έμ œκ°€ λ°œμƒν•˜λƒλ©΄, λ°”μ΄νŠΈ 슀트림의 λ°°μ—΄ λ‚΄λΆ€μ˜ 값을 직접 μ ‘κ·Όν•΄ μˆ˜μ •μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€.

이 μƒνƒœλ‘œ objectInputStream을 μƒμ„±ν•˜κ³ , readObjectλ₯Ό ν•œλ‹€λ©΄ κ·ΈλŒ€λ‘œ 생성이 λ©λ‹ˆλ‹€. 기쑴의 μƒμ„±μžμ—μ„œλŠ” validationλ‘œμ§μ„ λ„£μ–΄μ„œ κ°’μ˜ μœ νš¨μ„±μ„ νŒλ‹¨ν–ˆμ§€λ§Œ, readObjectλ₯Ό 톡해 λ§Œλ“€μ–΄μ§„ κ°μ²΄λŠ” 보이지 μ•ŠλŠ” λ‹€λ₯Έ μƒμ„±μžλ₯Ό μ‚¬μš©ν•˜κ²Œ λ˜μ–΄λ²„λ¦½λ‹ˆλ‹€.

 

이λ₯Ό λ°©μ–΄ν•˜λŠ” λ°©λ²•μœΌλ‘œλŠ”, μ»€μŠ€ν…€ 직렬화λ₯Ό μ‚¬μš©ν•˜λŠ” 방법이 μžˆμŠ΅λ‹ˆλ‹€. readObjectλ₯Ό μƒˆλ‘­κ²Œ μ •μ˜ν•˜λŠ” λ°©μ‹μœΌλ‘œ, 기쑴의 objectInputStream.defaultReadObject() λ©”μ„œλ“œλ₯Ό 톡해 기쑴의 역직렬화 과정을 μ‹œν‚€κ³ , 좔가적인 validation μ½”λ“œλ₯Ό 여기에 μ‚½μž…ν•΄μ£Όλ©΄ μ΄λŸ¬ν•œ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
	objectInputStream.defaultReadObject(); // 기본적인 역직렬화 κ³Όμ •
    // μƒλž΅, 좔가적인 validation μ½”λ“œ.
}

 

2) 싱글톀 문제

 

싱글톀 νŒ¨ν„΄μœΌλ‘œ μ–΄λ– ν•œ 클래슀λ₯Ό λ§Œλ“€κ³ , 이λ₯Ό 직렬화 κ°€λŠ₯ν•˜λ„λ‘ Serializable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν–ˆλ‹€κ³  ν•©μ‹œλ‹€.

싱글톀 객체λ₯Ό λ‹€μ‹œ 역직렬화 ν•˜λ©΄, μ‹±κΈ€ν†€μ˜ νŠΉμ„±μ„ μžƒμ–΄λ²„λ¦¬κ²Œ λ©λ‹ˆλ‹€. readObjectκ°€ 호좜되면 λ‹€λ₯Έ 객체가 μƒμ„±λ˜κ²Œ λ©λ‹ˆλ‹€. 싱글톀은 단 ν•˜λ‚˜μ˜ 객체만 μ‘΄μž¬ν•΄μ•Ό ν•œλ‹€λŠ” 것을 항상 μœ μ§€ν•˜λŠ”λ° 이λ₯Ό κΉ¨λ²„λ¦¬κ²Œ λœλ‹€λŠ” 것이죠.

 

μ΄λŸ¬ν•œ 싱글톀 문제λ₯Ό ν•΄κ²°ν•˜λ €λ©΄ readResolve()λ₯Ό μ •μ˜ν•˜λ©΄ λ©λ‹ˆλ‹€. readResolve() λ©”μ†Œλ“œλŠ” readObject()κ°€ 호좜된 이후에 호좜되게 λ©λ‹ˆλ‹€. 역직렬화λ₯Ό 거친 객체λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³ , readResolve()μ—μ„œ λ°˜ν™˜ν•˜λŠ” 객체λ₯Ό μ‚¬μš©ν•˜κ²Œ 되기 λ•Œλ¬Έμ—, 싱글톀 문제λ₯Ό ν•΄κ²°ν•  수 있죠.

 

λ‹€λ§Œ 이 경우, 클래슀의 ν•„λ“œ 쀑에, μΈμŠ€ν„΄μŠ€ λ³€μˆ˜κ°€ μ‘΄μž¬ν•˜λŠ” κ²½μš°μ—λŠ” 직렬화/역직렬화가 λ˜μ§€ μ•Šν† λ‘ transient ν‚€μ›Œλ“œλ₯Ό λΆ™μ—¬μ•Ό ν•©λ‹ˆλ‹€. κ·Έλž˜μ•Ό μ°Έμ‘°ν•„λ“œμ˜ μ˜μ—­κ°’μ„ ν›”μ³μ˜€λŠ” ν–‰μœ„λ₯Ό 막을 수 μžˆλ‹€κ³  ν•©λ‹ˆλ‹€. 이 뢀뢄은 좔후에 곡뢀λ₯Ό 더 ν•΄λ΄μ•Όκ² μŠ΅λ‹ˆλ‹€.

 

λͺ¨λ“  μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μ— μ‚¬μš©ν•΄μ•Ό ν•˜κ³ , 이λ₯Ό κ°„κ³Όν•œλ‹€λ©΄ λ³΄μ•ˆ λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

싱글톀같이 객체 갯수 ν†΅μ œ ν•΄μ•Ό ν•˜λŠ” μƒν™©μ—λŠ” readResolveλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 ꡉμž₯히 λΆˆνŽΈν•˜κ²Œ λ©λ‹ˆλ‹€.

 

 

μžλ°” μ§λ ¬ν™”λŠ” 생각할 것이 λ§Žμ€ κΈ°μˆ μ΄μ—ˆμŠ΅λ‹ˆλ‹€. μ•„λ¬΄λŸ° 생각 없이 μ‚¬μš©ν•˜λ‹€κ°€λŠ” μ—¬λŸ¬ λ¬Έμ œκ°€ λ°œμƒν•  μ—¬μ§€κ°€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

κ·Έλž˜μ„œ 10λΆ„ ν…Œμ½”ν†‘μ—μ„œλ„ μ›¬λ§Œν•˜λ©΄ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 것을 ꢌμž₯ν–ˆμŠ΅λ‹ˆλ‹€. μƒˆλ‘œμš΄ μ‹œμŠ€ν…œμ— λ°”μ΄νŠΈ 슀트림으둜 λ³€ν™˜ν•˜λŠ” 쒋은 λ§€μ»€λ‹ˆμ¦˜μ΄ 많기 λ•Œλ¬Έμž…λ‹ˆλ‹€. 

 

예λ₯Ό λ“€μ–΄, 크둜슀 ν”Œλž«νΌμ— μ ν•©ν•œ 데이터 ν‘œν˜„μœΌλ‘œ JSON, CSV, ν”„λ‘œν† μ½œ 버퍼 등을 μ‚¬μš©ν•˜λŠ” 것을 ꢌμž₯ν•œλ‹€κ³  ν•˜λ„€μš”.

μ΄νŽ™ν‹°λΈŒ μžλ°”μ—μ„œλ„ 직렬화 νŒŒνŠΈμ—μ„œ λ§Žμ€ λ‚΄μš©μ„ 닀루고 μžˆλ‹€λ‹ˆ, μΆ”κ°€ ν•™μŠ΅μ„ 해보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.

 

 

 

 

🏝 좜처

[링크] https://blog.naver.com/kkson50/220564273220 (SerialVersionUID)
[링크] https://www.youtube.com/watch?v=3iypR-1Glm0 (10λΆ„ ν…Œμ½”ν†‘ : μžλ°” 직렬화)
μ €μž‘μžν‘œμ‹œ λΉ„μ˜λ¦¬ 동일쑰건 (μƒˆμ°½μ—΄λ¦Ό)

'β˜• μžλ°” : JAVA' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[Effective Java] μƒμ„±μž λŒ€μ‹  정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œ μ‚¬μš©ν•˜κΈ°  (0) 2023.01.06
[Java] μƒμ†λŒ€μ‹  ꡬ성(Composition)을 μ‚¬μš©ν•˜μž  (0) 2022.12.08
[Java] μƒμ†μ˜ μž₯단점, 상속은 μ–Έμ œ 써야 ν•˜λŠ”κ°€?  (1) 2022.12.07
[Java] 상속(Inheritance) μ‚¬μš©λ²•κ³Ό 상속을 μ‚¬μš©ν•˜λŠ” 이유  (0) 2022.12.06
    'β˜• μžλ°” : JAVA' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€
    • [Effective Java] μƒμ„±μž λŒ€μ‹  정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œ μ‚¬μš©ν•˜κΈ°
    • [Java] μƒμ†λŒ€μ‹  ꡬ성(Composition)을 μ‚¬μš©ν•˜μž
    • [Java] μƒμ†μ˜ μž₯단점, 상속은 μ–Έμ œ 써야 ν•˜λŠ”κ°€?
    • [Java] 상속(Inheritance) μ‚¬μš©λ²•κ³Ό 상속을 μ‚¬μš©ν•˜λŠ” 이유
    개발자 HOON
    개발자 HOON
    쒋은 λ°±μ—”λ“œ μ—”μ§€λ‹ˆμ–΄κ°€ 되기 μœ„ν•œ 기둝을 λͺ¨μ•˜μŠ΅λ‹ˆλ‹€. # μ£Όλ‹ˆμ–΄ # λ°±μ—”λ“œ # 개발자

    ν‹°μŠ€ν† λ¦¬νˆ΄λ°”