'Serializable'에 해당되는 글 1건
- 2008.08.14 객체직렬화 Serializable
출처 http://blog.naver.com/kinpman/20649765
객체 직렬화는 메모리에 생성된 클래스 객체의 멤버변수의 현재상태를 그대로 보존해서 파일에 저장하거나 네트워크를 통해 전달할 수 있는 기능을 말한다. 객체 직렬화는 멤버변수의 값을 보존한다거나 다른 네트워크에 있는 호스트에 값을 보낸다던가 할때 사용된다. 객체 직렬화는 자바 1.1 이후에 도입이 되었는데 그 이유는 RMI와 Bean 때문이었다. RMI는 원격객체통신을 지원해야 하기 때문에 객체가 그대로 이동할 수 있어야 한다. 따라서 이를 지원하기 위해서 객체직렬화가 필수이다. 그리고 Bean은 설계시 상태에 대한 정보를 지정할때 이 객체직렬화를 사용하면 편하게 객체 상태를 저장할 수 있다. 그 외에도 네트워크 프로그램이나 파일 프로그램에서 객체직렬화를 사용하면 코딩도 짦아지고 작업이 수월하게 된다.
자바에서는 객체 직렬화 기능을 지원하기 위해서 Serializable 인터페이스, ObjectInputStream 클래스, ObjectOutputStream클래스, transient 키워드가 사용된다. Serializable 인터페이스는 자바가상머신에게 직렬화를 사용함을 알리는 역활을 하고 ObjectInputStream 클래스, ObjectOutputStream클래스는 객체를 입출력을 하기 위해 사용되는 클래스이다. 이들은 다 java.io 패키지에 정의되어 있다.
15장 객체직렬화
15.1 객체직렬화의 개념
객체 직렬화란 객체의 내용을 바이트 단위로 변환하여 파일 또는 네트워크를 통해서 송수신(스트림)이 가능하게 만들어 주는 것을 말한다. 여기서 객체란 멤버변수의 메모리만으로 구성된 것을 말한다. 따라서 객체 직렬화에서 메서드와 생성자는 제외된다는 것을 있지 말자.
이렇게 객체를 직렬화 함으로써 얻을 수 있는 장점은 객체 자체의 내용을 입출력 형식에 구애 받지 않고 객체를 파일에 저장함으로써 영속성을 제공할 수 있고, 객체 자체를 네트워크를 통하여 손쉽게 교환할 수 있게 된다.
객체 직렬화는 자바 1.1 이후에 도입이 되었는데 그 이유는 RMI와 Bean 때문이었다. RMI는 원격객체통신을 지원해야 하기 때문에 객체가 그대로 이동할 수 있어야 한다. 따라서 이를 지원하기 위해서 객체직렬화가 필수이다. 그리고 Bean은 설계시 상태에 대한 정보를 지정할때 이 객체직렬화를 사용하면 편하게 객체 상태를 저장할 수 있다. 그 외에도 네트워크 프로그램이나 파일 프로그램에서 객체직렬화를 사용하면 코딩도 짦아지고 작업이 수월하게 된다.
위의 그림을 보면 객체직렬화 구조에 대해 잘 나타나고 있다. 먼저 String 과 int 형인 멤버변수를 가진 클래스를 컴파일을 시키고 실행을 하면 각 변수에 값이 대입되면서 자바가상머신의 메모리에 자리를 잡을 것이다. 이때 컴의 전원을 끄거나 한다면 이 변수의 값은 사라지고 말것이다. 하지만 이 값을 영구 보존을 한다던지 누군가에게 이 값을 그대로 전달하고자 한다면 객체직렬화를 사용해야 한다. 실행되어서 생성된 값을 가진 클래스 객체를 직렬화 해서 파일에 저장을 한다던지 네트워크를 통해서 전달하면 그 객체의 값(멤버변수의 값이다)은 그대로 복원되어 사용할 수 있다.,.. 이 얼마나 편리한가...으하하하하하...
자. 진정하고 정리해 보자..
객체직렬화란????
객체 직렬화 : 객체를 한 줄로 늘어선 바이트 형태로 만드는 것 ---> 전송이 가능해짐
여기서 객체란 값이 할당된 멤버변수로만 구성되고 객체 직렬화에서 메서드와 생성자는 제외됨
객체를 이용한 메서드 호출 : 객체가 보유하고 있는 값과 메서드의 형태를 알면 호출가능
객체 직렬화의 사용 : 객체 자체를 저장(영구보존)하거나 네트워크를 통해 전송하는 경우
객체 직렬화의 장점 : 객체 영구보존 가능. 데이터의 복구 가능해 진다.
Serializable 인터페이스와 ObjectInputStream 클래스,ObjectOutputStream클래스
객체 직렬화를 하기 위해서 먼저 객체를 객체직렬화가 가능하도록 Serializable 인터페이스를 구현해야 한다. 그리고 ObjectInputStream 클래스와 ObjectOutputStream클래스는 객체를 입출력을 하기 위해 사용되는 클래스이다. 이들은 다 java.io 패키지에 정의되어 있다. 각각 알아보자.
1> Serializable 인터페이스
객체 직렬화를 하기 위해서 먼저 객체를 객체직렬화가 가능하도록 Serializable 인터페이스를 구현해야 한다. 이 인터페이스는 객체직렬화가 제공되어야 함을 자바가상머신에 알려주는 역활을 한다. Serializable 인터페이스는 다른 인터페이스와는 달리 구현해야 할 메서드가 없으므로 단지 선언만 해주면 된다. 형식은 다음과 같다.
|
2> ObjectInputStream 클래스
ObjectInputStream 클래스는 파일에 저장되어 있는 객체 또는 네트워크를 통해 직렬화되어 전달된 객체를 직렬해제 하는 기능을 제공해 주고 있다. 한가지 주의할 점은, java.io.Serializable 인터페이스와 java.io.Externalizable 인터페이스를 지원해 주는 객체에 대해서만 가능하다는 것인데, 이는 등록된(즉 Serializable 인터페이스와 Externalizable 인터페이스를 구현한 클래스 객체) 객체를 말한다. 이 때, readObject 메소드를 이용하여 스트림으로부터 직렬화된 객체를 읽을 수 있다. 그리고, 이렇게 읽은 객체는 배열, 문자열, 또는 각 객체 등 원래의 형으로 캐스팅 해 주어야 한다.
가. 주요 메서드
ㅁ ObjectInputStream(InputStream in): 주어진 입력 스트림에 대한 ObjectInputStream 객체를 생성.
ㅁ public final Object readObject() throws OptionalDataException, ClassNotFoundException, IOException
: 직렬화된 객체를 스트림으로부터 읽어들인다. --> 복원한다, 직렬화를 해제한다. 이렇게도 말한다.
: 주의>> 반드시 읽어들이려는 객체는 Serializable 인터페이스와 Externalizable 인터페이스를 구현한 클래스 객체이여야 한다.
나. 사용 예
|
3> ObjectOutputStream 클래스
ObjectOutputStream 클래스는 객체들을 출력하는 기능을 제공해 주고, 출력 스트림에 출력하기 전에 직렬화를 수행한다. ObjectOutputStream 클래스는 자바 기본형 데이터 또는 객체들을 파일에 저장하거나 네트워크를 통해 전달하기 위해 전달할 객체를 직렬화하는 기능을 제공해 준다. 이 클래스도 역시 ObjectInputStream 클래스와 마찬가지로 java.io.Serializable 인터페이스와 java.io.Externalizable 인터페이스를 구현한 객체에 대해서만 가능하다. 이 때, writeObject 메소드를 이용하여 스트림에 직렬화된 객체를 출력한다.
가. 주요 메서드
ㅁ ObjectOutputStream(OutputStream out): 주어진 출력 스트림에 대한 ObjectOutputStream 객체를 생성.
ㅁ public final void writeObject(Object obj) throws IOException : 출력 스트림에 객체(obj)를 출력한다. 역시 출력하려는 객체(obj)는 반드시 Serializable 인터페이스와 Externalizable 인터페이스를 구현한 클래스 객체이여야 한다.
나. 사용 예
|
자, 객체직렬화를 하기 위해서 필요한 클래스들을 살펴보았다. 정리를 한번 하고 코드를 작성해 보자.
|
이제 객체직렬화를 해서 네트워크로 객체를 전송해서 복원해 보자.
아래 소스를 보면 서버측에서 우선 Serial_Server 객체 st1과 st2 두개 를 생성한다. 각 객체의 멤버변수의 값은 다르다. 이 두 개의 객체를 ObjectOutputStream으로 직렬화를 시켜 접속된 클라이언트에게 전송한다. 그러면 클라이언트측은 이 두 객체를 받아서 ObjectInputStream으로 읽어들인다.... 소스를 파헤쳐보자... 우선 네트워크부분은 13장에서 다루었으므로... 넘어간다........
Serial_Server.java --> 서버측
|
Serial_Client.java --> 클라이언트측
|
<< 실행 결과 >>
서버측
|
클라이언트측
|
|
transient
객체 직렬화를 사용하면 객체의 멤버변수를 영구히 보존한다는 장점이 있다. 하지만 보존하고 싶지 않을 경우도 있을 것이다. 예를 들면 클래스를 만들다보니 중요하지 않는 변수가 멤버변수가 될 수도 있고 패스워드나 중요한 정보(남에게 알려져서는 안되는 그런... 여성의 몸무게? )가 객체직렬화로 저장이 되면 누구나 내용을 복원할 수 있으니 문제가 된다. 이런 경우에 사용하는 것이 바로 transient 키워드이다.
객체직렬화시 transient 키워드는 저장할 필요가 없는 멤버 변수를 지정할 때 사용된다. transient 키워드를 저장할 필요가 없는 멤버 변수 앞에 선언해 주면 객체직렬화 대상에서 제외가 된다. 따라서 이 키워드가 사용된 멤버변수를 복원을 시키면 기본 초기값으로 설정되어 출력된다.
앞장에서는 네트워크로 객체직렬화를 해봤지만, 이번에는 파일로 객체 직렬화를 해서 transient 키워드를 사용해 보자.
Serial_File.java
|
<< 실행 결과 >>
|
결과를 보면 transient 키워드를 사용한 pass 변수만이 값이 지워져서 'null'값으로 출력되는 것을 볼 수 있다. transient 키워드를 지우고 실행을 시켜보자... 그러면 pass 값이 저장된 것을 알 수 있다.
|
Externalizable
1> Externalizable 인터페이스란
Externalizable 인터페이스는 Serializable 인터페이스의 하위 인터페이스로서 보다 효율적인 직렬화를 위해서 사용된다. 이 인터페이스는 Serializable 인터페이스와 같은 기능은 하되 좀더 완벽한 제어를 할 수 있다. 또한 메서드를 가지고 있지 않은 Serializable 인터페이스와 달리 Externalizable 인터페이스는 writeExternal 메소드와 readExternal 메소드를 정의하고 있으며, 이 두 개의 메소드가 객체의 전체 입출력을 담당하게 된다. 따라서 이 인터페이스를 사용하고자 한다면 이 두개의 메서드를 반드시 오버라이딩을 해주어야 한다.
Externalizable 인터페이스 원형 |
|
2> Externalizable 인터페이스 주요 메서드
ㅁ public void readExternal(ObjectInput in) throws IOException , ClassNotFoundException
: 만약 읽으려는 객체가 기본형이라면 DataInput 인터페이스의 메소드들(readXXX()류)을 사용하고, 객체가 오브젝트, 스트링, 배열의 경우에는 ObjectInput 인터페이스의 readObject 메소드()를 호출하는 것으로, 오브젝트의 내용을 복원한다. 즉, 이 메서드는 객체의 유형에따라 적절한 readXXX() 메서들를 사용해서 이 객체가 포함하고 있는 내용을 그대로 읽을 수 있도록 한다.
ㅁ public void writeExternal(ObjectOutput out) throws IOException
: 만약 출력하려는 객체가 기본형이라면 DataOutput 인터페이스의 메소드들(writeXXX()류)을 사용하고, 객체가 오브젝트, 스트링, 배열의 경우에는 ObjectOutput 인터페이스의 writeObject 메소드()를 호출하는 것으로, 오브젝트의 내용을 출력스트림에 쓴다. 즉, 이 메서드는 객체의 유형에따라 적절한 writeXXX() 메서들를 사용해서 객체를 출력한다.
3> Externalizable 인터페이스 예
여기서는 두 개의 클래스로 예제를 작성했다. 한 클래스는 Externalizable 인터페이스를 구현해서 Externalizable 인터페이스에 정의된 두 메서드, writeExternal 메소드와 readExternal 메소드를 재정의하는 클래스 하나(여기서는 External_Test 클래스이다.), 다른 클래스는 External_Test 클래스의 writeExternal 메소드와 readExternal 메소드를 사용해서 객체 질렬화를 만들고 읽기를 담당한다.(여기서는 External_InOut 클래스이다.)
External_Test .java
|
External_InOut.java
|
<< 실행 결과 >>
|
애플릿도 직렬화된 형태로 저장될 수 있다. 저장하는 방법은 어플리케이션과 같다. 저장된 애플릿을 다시 블러낼때에는 조금 다르다. 애플릿 태그의 code 속성대신 object 속성을 지정하면 직렬화된 객체를 다시 풀어서 재생될 수 있다. 즉 어플리케이션에서 필요했던 ObjectInputStream 클래스가 필요없다. 그일을 object 지시자가 대신해 준다. 이때 code 와 object 지시어는 동시에 사용될 수 없으며 둘 중 하나는 반드시 있어야 한다. 이 경우 애플릿의 init 메소드는 호출되지 않으며, start 메소드만이 호출된다는 점에 유의해야 한다. 먼저 소스를 보자.
SerializedApplet.java
|
<< 실행 하기 >>
- 우선 컴파일 한다.
C:\javaExample> javac SerializedApplet .java
- 애플릿을 실행하기 전에 main메서드를 실행시킨다. 그이유는 애플릿 객체를 직렬화를 담당하는 것은 실제 메인 메서드이므로..
C:\javaExample> java SerializedApplet
init()
init()메서드가 호출된다. 당연하다. 메인 메서드에서 호출하므로.. 호출해주는 이유는 애플릿이 저장되기 위해서는 최소한 init()메서드가 호출된 상태여햐 한다. 이제 폴더에 applet.ser 파일이 생길 것이다.
- 이제 애플릿을 실행시켜 보자. 그러면 html문서가 필요하다. 문서의 내용은 다음과 같다.
<applet object="applet.ser" width="300" height="200"></applet>
소스를 보면 code 지시자 대신에 object 지시자가 사용되었고 값으로 애플릿 객체가 저장되어 있는 파일명이 들어온다. 이제 이 태그로 애플릿은 되살릴 수 있다. 즉 어플리케이션에서 필요했던 ObjectInputStream 클래스가 필요없다. 그일을 object 지시자가 대신해 준다.
- 애플릿 뷰어 혹은 브라우저에서 실행한다.
C:\javaExample> appletviewer SerializedApplet .htm
start()
'My work space > Java' 카테고리의 다른 글
awt와 swing의 차이점 (0) | 2008.08.20 |
---|---|
Basic Java - Swing (0) | 2008.08.14 |
[아시나요?]static만이 가능한 몇가지 특징 (0) | 2008.08.14 |
[아시나요?]JAR 파일 만들기 , 이용 (0) | 2008.08.14 |
쓰레드 구구단 예제 입니다 (0) | 2008.08.14 |