Skip to the content.

- 학습 목표 달성 확인 목록

- [] 바이트 배열을 이용하여 데이터를 읽을 때 바이트 배열의 크기는 어느 정도가 적당한가?

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();
  }
}