Java/네트워크 통신

[Java] 91. 고수준 스트림 (Object)

Song hyun 2024. 5. 22. 10:19
728x90
반응형

[Java] 91. 고수준 스트림 (Object)

1. ObjectInputStream / ObjectOutputStream 

2. 직렬화와 역직렬화

3. 시나리오 코드 (1): 객체 직렬화하기

4. 시나리오 코드 (2): 객체 역직렬화하기

 


1. ObjectInputStream / ObjectOutputStream 

-ObjectInput/OutputStream은 객체를 직렬화하여 파일에 쓰거나, 네트워크에 전송하고, 이를 다시 역직렬화하여, 객체로 복원할 때 사용하는 자바의 입출력 클래스이다.

 

-객체 스트림(Object~Stream)은 메모리상에 존재하는 객체를 직접 파일로 입출력해줄 수 있는 스트림이다.

자바에서 객체 안에 저장되어 있는 내용을 파일로 저장하거나, 네트워크를 통해 다른 곳으로 전송하려면 객체를 바이트 형태로 분해해야 한다. 즉, 객체 스트림을 사용하기 위해서는 먼저 파일을 직렬화(Serializable)해야 한다는 것이다.

 


 

2. 직렬화와 역직렬화

(1) 직렬화(Serialization): 객체의 상태를 바이트 스트림으로 변환하여, 파일에 저장하거나 네트워크를 통해 전송할 수 있게 만드는 과정이다. 

(2) 역직렬화(Deserialization): 바이트 스트림으로 변환된 객체를 다시 객체 형태로 복원하는 과정이다.

 

*직렬화(Serialization)에서 "바이트 스트림으로 변환한다"는 말의 의미는, 객체의 상태(필드 값 등)를 바이트 단위의 데이터로 변환하고, 이를 스트림을 통해 입출력이 가능하게끔 만드는 과정을 뜻한다!

** 특정 클래스를 직렬화하기 위해서는 해당 클래스의 상위 부모, 또는 그 클래스를 바로 Serializable 구현(implements)

야한다.

 

 

? 왜 Serializable 인터페이스를 구현할까?

-Serializable 인터페이스는 마커 인터페이스로, 이 인터페이스를 구현하는 클래스는 직렬화할 수 있다는 의도를 명확하게 하는 용도로 쓰인다. 자바 런타임 환경(JRE)에 해당 객체가 직렬화/역직렬화에 적합함을 알려주는 인증 마크인 셈!

 

? serialVersionUID의 사용 이유?

:serialVersionUID는 클래스의 버전 관리를 위해 사용되는 고유 식별자이다. 직렬화된 객체를 역직렬화할 때, 저장된 객체의 serialVersionUID와 클래스의 serialVersionUID가 일치하는지 검사해, 객체의 호환성을 체크한다.

 

-버전 관리: 클래스가 변경되면(ex: 메서드 변경) 기존의 직렬화된 객체와 호환성을 유지하기 위해, serialVersionUID를 정의하기도 한다.

-자동 생성: serialVersionUID를 명시하지 않으면, 자바 컴파일러가 이를 자동적으로 생성한다. 이는 클래스의 변경에 따라 달라질 수도 있어, 명시적으로 직접 정의하는 것이 좋다!


3. 시나리오 코드 (1): 객체 직렬화하기

-아래의 코드를 살펴보자.

 

-Person 클래스는 클래스를 직렬화하기 위해 serializable을 구현했다. 

새로운 Person 클래스에 "손흥민", 30이라는 멤버 변수를 초기화했다.

 

Person 클래스는 Serializable을 구현하고 있기 때문에 직렬화가 되고 있는 상태이다.

writeObject 출력 시, 아래와 같은 결과가 나오는 이유이다!

// 객체 직렬화
		try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"))) {
			Person person = new Person ("손흥민", 30);
			oos.writeObject(person);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("------------");

 

4. 시나리오 코드 (2): 객체 역직렬화하기

-시나리오 코드(1)에서 작성한 person.txt.

아래 코드에서는 해당 txt 파일을 FileInputStream-ObjectInputStream을 통해 읽어들이고 있다.

(위의 시나리오 코드(1)에서는 "손흥민", 30을 역직렬화 하여 바이트화했다.)

 

-새로운 Person 클래스를 생성하고, 읽어들인 데이터(Object: 최상위 클래스)를 Person형으로 다운 캐스팅하여 다시 출력하고 있다. 즉, 역직렬화한 뒤에는 객체의 본래 값 그대로이기 때문에 "손흥민",30이 출력된다.

// 객체 역직렬화
		try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"))){
			// 문자 기반 데이터를 읽으면 <--- 스트링 값 추출해서 코드상에 활용할 수 있도록 
			// Object 만드는 코딩을 해야한다.
			Person person = (Person)ois.readObject();
			// ois를 person으로 다운캐스팅(Object->person)
			// readObject = final 타입 메서드
			// final 타입 메서드: 상속 후 재정의할 수 없게 한 메서드
			System.out.println(person);
		} catch (Exception e) {
			// TODO: handle exception
		}

 

728x90
반응형