[ Review 복습 ]
Stream
java.io의 대표 abstract class
Byte Stream 1 byte (음원, 이미지 등) |
Character Stream 2 byte (텍스트 등) |
|
입력 | InputStream | Reader |
출력 | OutputStream | Write |
Node Stream : 연결되는 스트림(없으면 생성), socat
Processing Stream : 기능 동작하는 스트림(보조, 부가기능)
[코딩 패턴]
Node Stream | Processing Stream | |
Output | new FileWriter | new PrintWriter | .println() 출력 | .close() |
Input | new FileReader | new BufferedReader | .readLine() 읽기(입력) | .close() |
* 자세한 설명 : https://creamilk88.tistory.com/38
[ IO ]
객체 직렬화 ( Object Serialization )
: 메모리 상에 있는 객체 정보를 외부로 전송할 수 있는 상태로 만드는 것
java.io.Serializable
> 객체 직렬화를 위해서는 해당 객체는 java.io.Serialization interface를 implements 해야 한다.
즉, 해당 객체는 Serializable 계층구조의 하위 객체여야 한다.
(그렇지 않으면, jvm이 java.io.NotSerializableException을 발생시킴)
> 객체 직렬화 시 사용할 스트림
ObjectOutputSream - writeObject(Object o)
> 객체 역직렬화 시 사용할 스트림
ObjectInputStream - readObject() : Object
객체 직렬화 예제
1. Output 예제
package step1;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import model.Person;
public class TestObjectOutput {
public static void main(String[] args) {
String savePath = "C:\\kosta203\\iotest\\person.obj";
try
{
// 1. 경로(savePath)에 있는 파일 읽기(연결) & person.obj 파일 생성
FileOutputStream fos = new FileOutputStream(savePath);
// 2. Person 객체를 직렬화하여 제공
ObjectOutputStream oos = new ObjectOutputStream(fos);
// 3. Person object 정보를 person.obj 파일에 입력
Person p = new Person("아이유", "판교", "자바킹");
oos.writeObject(p);
// 4. exception 없을 시 출력
System.out.println("객체 직렬화하여 person.obj에 Person p 저장 완료");
// 5. output object 닫기
oos.close();
}
catch (FileNotFoundException fe)
{
fe.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
[ Node Stream : 장치에 연결 ]
1. FileOutputStream은 파일에 연결
← FileOutputStream fos = new FileOutputStream(savePath);
[ Processing Stream (보조 스트림) : 다양한 기능을 지원 ]
2. ObjectOutputStream은 객체 직렬화해 제공
← ObjectOutputStream oos = new ObjectOutputStream(fos);
3. Person object 정보를 Object stream(oos)에 입력하여 출력
←Person2 p2 = new Person2("아이유", "판교", "자바킹");
←oos.writeObject(p2);
객체 직렬화가 되지 않아, exception 발생
model object를 객체 직렬화해주기 위해 Serializable interface를 implement해주어야 함
⇒ Serializable interface를 implements 해주어야만 직렬화 가능한 객체가 된다.
package model;
import java.io.Serializable;
//super class
public class Person implements Serializable{
/**
* serialVersionUID : class의 지문
* 클래스 버전을 명시함으로써, 객체 직렬화와 역직렬화 시 호환성을 위해 사용
*/
private static final long serialVersionUID = 8434327299042305734L;
private String name;
private String address;
private String password;
public Person(String name, String address, String password) {
this.name = name;
this.address = address;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
정상 수행 됨.
2. Input 예제
package step1;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import model.Person;
public class TestObjectInput {
public static void main(String[] args) {
String savePath = "C:\\kosta203\\iotest\\person.obj";
try
{
// 1. 경로(savePath)에 있는 파일 가져오기(연결)
FileInputStream fis = new FileInputStream(savePath);
// 2. input object stream(object) 객체 생성
ObjectInputStream ois = new ObjectInputStream(fis);
// 3. input object(ois)에 담긴 정보 : Object type으로 반환
// 타입을 Object -> Person로 downcasting 필요
Person p = (Person)ois.readObject();
// 4. 정보 하나씩 출력
System.out.println(p.getName());
System.out.println(p.getAddress());
System.out.println(p.getPassword());
/* 출력값:
* 아이유
* 판교
* 자바킹
*/
// 5. input object 닫기
ois.close();
}
catch (FileNotFoundException fe)
{
fe.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException ce) {
ce.printStackTrace();
}
}
}
Person object가 이미 객체직렬화되어있어, 문제없이 수행된다.
> serialVersionUID
: class의 지문
: 클래스 버전을 명시함으로써, 객체 직렬화와 역직렬화 시 호환성을 위해 사용
(private static final long serialVersionUID = 8434327299042305734L;)
: 정보를 가져올 클래스(A)가 변경되더라도, 오류가 나지않고 Input class에서 A에서 변경된 사항이 적용되어 실행된다.
: 직렬화 대상 클래스 (Serializable 을 implements하는 클래스)들은 개별 클래스마다 JVM에 의해 자신의 serialVersionUID를 가진다. 이 때, 클래스의 정보(인스턴스 변수)가 변경되면 다시 해당 클래스의 serialVersionUID가 재할당된다.
이 경우에서 클래스의 정보가 업데이트 될 경우 기존의 클래스로 직렬화된 정보를 역직렬화하여 입력받으려 할 경우 Exception이 발생하게 된다. 이를 해결하기 위하여, 클래스 업데이트에 따른 직렬화와 역직렬화의 호환성을 위해 serialVersionUID를 직접 명시할 것을 권장한다.
> transient keyword [트랜지언t]
: 변수 앞에 지정하는 modifier
: 객체 직렬화 대상에서 해당 인스턴스 변수의 정보를 제외할 때 사용
(객체가 직렬화되어 외부로 전송될 때, 특정 인스턴스 변수의 정보를 직렬화 대상에서 제외하고 할 때, transient 키워드를 이용한다.)
transient 사용 예제
/ object class
package model;
import java.io.Serializable;
public class Person2 implements Serializable{
private String name;
private String address;
private transient String password;
public Person2(String name, String address, String password) {
this.name = name;
this.address = address;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
object의 password변수를 transient modifier 로 지정 : 직렬화 대상에서 제외
← private transient String password;
/ input class
package step1;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import model.Person2;
public class TestObjectInput {
public static void main(String[] args) {
String savePath = "C:\\kosta203\\iotest\\person.obj";
try
{
// 1. 경로(savePath)에 있는 파일 가져오기(연결)
FileInputStream fis = new FileInputStream(savePath);
// 2. input object stream(file) 객체 생성
ObjectInputStream ois = new ObjectInputStream(fis);
// 3. input object(ois)에 담긴 정보 : Object type으로 반환
// Object -> Person로 downcasting 필요
Person2 p = (Person2)ois.readObject();
// 4. 정보 하나씩 출력
System.out.println(p.getName());
System.out.println(p.getAddress());
System.out.println(p.getPassword());
/* 출력값:
* 아이유
* 판교
* null
*/
// 5. input object 닫기
ois.close();
}
catch (FileNotFoundException fe)
{
fe.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException ce) {
ce.printStackTrace();
}
}
}
password는 transient modifier가 지정되어 있어 직렬화 대상에서 제외되었으므로,
null이 반환된다.