먼저 일반적으로 사용되는 ObjectOutputStream의 구조를 보자

FileOutputStream ostream = new FileOutputStream("t.tmp");
ObjectOutputStream p = new ObjectOutputStream(ostream);

p.writeInt(12345);
p.writeObject("Today");
p.writeObject(new Date());

p.flush();
ostream.close();


이를 보면 대부분 ObjectOutputStream은 FileOutputStream과 같이 사용되는 것을 볼 수 있다.

java에서 구성되고 있는 구조를 보자



이를 보면 ObjectOutputStream은 OutputStream을 상속받고 있으며,

Source를 보면 OutputStream을 상속받으면서도, 동시에 OutputStream을 맴버 변수로 가지고 있다.

때문에 ObjectOutputStream은 OutputStream을 생성자에서 인자로 받을수 있다.

이때 FileOutputStream은 OutputStream을 상속받기 때문에

ObjectOutputStream의 생성자 인자로 들어갈 수가 있다.



위에서 보듯이 ObjectOutputStream은 어떤 객체이든 writeObject()를 수행하면, 모두 기록이 가능하다(단, Serializable하다면)

하지만, Serializable의 내부를 보면 아무것도 없다! 전혀!!!

왜? Serializable은 단지 직렬화 가능한 객체라는 것을 표시하는 것 뿐이기 때문이다.

이는 다른 관점에서 이야기하면 Serializable을 구현한 객체는 직렬화를 위해 그 어떤 작업이나 특성을 가지지 않는다는 것을 의미한다.

그럼 여기서 왜 java는 위와 같은 구조를 가지며, 어떻게 Serializable 표시가 된 객체를 저장하고 읽어올수가 있는것일까?

정답은 Class에 있다.

ObjectOutputStream의 writeObject()는 Object를 인자로 받아

Object의 getName() 메소드를 통해 해당 Class의 이름을 String으로 알아낸다.

이미 눈치빠르신 분은 알겠지만, ObjectInputStream에서 반대로 forName()과 같은 메소드를 통해 다시 Object를 Class화 시킨다.

(이때, UTF-8을 이용하여 정확한 Class명을 얻어올수 있다. 자세한것은 생략)

이와 비슷한 방법으로 Field들도 단위적으로 저장하고 읽어올수 있다.

이런 식으로 하여 Object를 그의 특성에 맞게 저장하고, 다시 그대로 복원이 가능해진 것이다.






그렇다면, 이를 이용해 간단한 SimpleObjectOutputStream을 설계해 보자.

이는 java library처럼 객체내에 reference 변수가 있다면 그까지 저장하진 않고, 단순 객체만을 저장하고, 읽어오도록 하자.

이때 중요한것은, 해당 Object에 대한 정보를 SimpleObjectOutputStream이 알아내서 처리하는 구조가 아닌,

해당 Object에게 OutputStream을 전달하여 해당 Object가 실제로 자기 특성에 맞게 저장하는 모습이 더 낫다고 생각한다.

때문에, Serializable은 writeObject()와 readObject()를 구현해야만 하며, SimpleObjectOutputStream은 내부적으로 해당 객체의 writeObject()를 호출해주어야 한다.



구조는 java library와 전적으로 동일하다.

하지만, 이때 SimpleObjectOutputStream은 인자로 받은 Object의 특성을 모두 알아내어 OutputStream에게 보내는 것이 아니라,

Object에게 OutputStream을 인자로 보내어 Object 스스로 알아서 저장하고 읽어오게 하는 방법으로 설계하면 된다.

+ Recent posts