- 학습 목표 달성 확인 목록
- [] 바이트 배열을 이용하여 데이터를 읽을 때 바이트 배열의 크기는 어느 정도가 적당한가?
byte[] buf = new byte[8192]; // 보통 8KB 정도 메모리를 준비한다.
- [] 상속을 이용한 입출력 기능 확장의 한계점을 이해하는가?

엄진영강사님 출처
DataFileInputStream과 DataByteArrayInputStream은 생성자를 제외하고 나머지 코드가 같다
안타깝게도 DataFileInputStream의 코드를 복사하지 않고 재사용할 방법이 없다
이것이 상속으로 기능을 확장했을 때의 한계점이다.
- [] 포함 관계를 통한 기능 확장을 구현할 수 있는가?
public class Exam0210 {
public static void main(String[] args) throws Exception {
// FileInputStream
// - 파일 저장소에서 데이터를 읽는 일을 한다.
FileOutputStream out1 = new FileOutputStream("temp/member.data");
// FileOutputStream + DataOutputStream
// - 문자열이나 자바 기본 타입의 데이터를 좀 더 쉽게 읽기
// - FileOutputStream 객체에 타입에 맞춰 데이터를 읽는 기능을 덧붙인다.
DataOutputStream out2 = new DataOutputStream(out1);
Member member = new Member();
member.name = "AB가각간";
member.age = 27;
member.gender = true;
out2.writeUTF(member.name);
out2.writeInt(member.age);
out2.writeBoolean(member.gender);
out2.close();
System.out.println("출력 완료!");
}
}
- [] 포함 관계와 상속을 이용하여 데코레이터 패턴을 구현할 수 있는가?
%[https://gist.github.com/osk2090/d9d10ff81ea7d86fbad1a9bcbd9741a6]

- [] Java Streamming API의 주요 클래스에 대한 계층도를 그릴 수 있는가?

- [] serialize(직렬화; 바이트 배열화)의 개념을 이해하는가?
Serializable 인터페이스를 구현한 클래스인 경우
컴파일 할 때 버전 번호를 부여한다
그래서 필드 추가/변경/삭제 시 버전 번호도 변경된다.

transient private 타입 변수이름;
// serialize 대상에서 제외할 필드는 transient로 선언한다.
//이유는 데이터의 왜곡을 막기 위함이다.
//출력한 파일을 조작해서 의도와 다른 값을 가지게 할 수 있기 때문이다.
//필드에 serialize 대상이 아니라고 표시하라!
//transient 한정자(modifier)를 붙인다.
//transient => 일시적인
- [] ObjectInputStream/ObjectOutputStrteam을 이용하여 인스턴스를 입출력 할 수 있는가?
%[https://gist.github.com/osk2090/d2d13fd79926101e6f02bb61423980e0]
- [] java.io.Serializable 인터페이스의 용도를 아는가?
public class 클래스이름 implements Serializable
버전을 부여하여 파일의 필드를 수정/삭제시 버전을 확인하여 버전이 다르면 예외를 발생시킨다.
- [] serialize 파일에 출력되는 내용은 무엇인가?
클래스 정보,필드 정보,필드값,버전 이 포함되어 있다.
- [] serialVersionUID 스태틱 필드의 용도를 아는가?
private static final long serialVersionUID = 100L;
//이렇게 변수를 만들어주면 클래스를 바꾸더라도 serialVersionUID는 이전과 같은 값을 갖게 한다.
- [] 파일 입출력을 프로그래밍 할 때 예외처리를 할 수 있는가?
// sum과 aver 필드는 getter 메서드만 둔다.
// setter를 제거한다.
public class Score3 implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int kor;
private int eng;
private int math;
// serialize 대상에서 제외할 필드는 transient로 선언한다.
transient private int sum;
transient private float aver;
public Score3() {
System.out.println("Score3()");
}
@Override
public String toString() {
return "Score3 [name=" + name + ", kor=" + kor + ", eng=" + eng + ", math=" + math + ", sum="
+ sum + ", aver=" + aver + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("setName()");
this.name = name;
}
public int getKor() {
return kor;
}
public void setKor(int kor) {
System.out.println("setKor()");
this.kor = kor;
compute();
}
public int getEng() {
return eng;
}
public void setEng(int eng) {
System.out.println("setEng()");
this.eng = eng;
compute();
}
public int getMath() {
return math;
}
public void setMath(int math) {
System.out.println("setMath()");
this.math = math;
compute();
}
// sum과 aver 필드처럼 내부 필드 값을 가지고 계산한 결과를
// 저장하는 경우 외부에서 직접 필드의 값을 설정하지 못하게 해야 한다.
// 즉 setter를 만들지 말라!
public int getSum() {
return sum;
}
public float getAver() {
return aver;
}
public void compute() {
this.sum = this.kor + this.eng + this.math;
this.aver = this.sum / 3f;
}
}
public class Test3_1 {
public static void main(String[] args) throws Exception {
FileOutputStream out0 = new FileOutputStream("temp/score.data");
ObjectOutputStream out = new ObjectOutputStream(out0);
Score3 score = new Score3();
score.setName("홍길동");
score.setKor(100); // setter 내부에서 compute()를 호출하여 sum과 aver를 자동 계산한다.
score.setEng(100);
score.setMath(100);
// 출력하기 전에 현재 Score3 인스턴스의 값을 출력해 보자!
System.out.println(score);
// 인스턴스 출력하기
// => 내부 필드의 값을 가지고 계산한 값을 보관하는 필드는
// 가능한 serialize 대상에서 제외해야 한다.
// => 왜?
// 출력 후 데이터의 왜곡을 막기 위함이다.
// 출력한 파일을 조작해서 의도와 다른 값을 가지게 할 수 있기 때문이다.
// => 방법?
// 필드에 serialize 대상이 아니라고 표시하라!
// transient 한정자(modifier)를 붙인다.
// transient => 일시적인
// => Score3 클래스의 sum 필드와 aver 필드에 transient를 붙이고
// 출력해보라!
// 해당 필드의 값이 출려되지 않을 것이다.
out.writeObject(score);
System.out.println("출력 완료!");
out.close();
}
}
public class Test3_2 {
public static void main(String[] args) throws Exception {
FileInputStream in0 = new FileInputStream("temp/score.data");
ObjectInputStream in = new ObjectInputStream(in0);
Score3 score = (Score3) in.readObject();
System.out.println(score);
// transient 필드는 보안상 serialize 되지 않기 때문에
// deserialize 한 후 계산을 다시 해야 한다.
// => 파일을 조작해서 합계와 평균을 왜곡하는 상황을 막을 수 있다.
score.compute();
System.out.println(score);
in.close();
}
}