32. 객체 출력하기 / ObjectOutputStream, ObjectInputStream
인스턴스를 통째로 입출력하기(객체 직렬화) // ObjectOutputStream
write object
단점: 출력 형식을 따라야함.
Board 객체를 writeObject()로 입력하면 ObjectOutputStream이 byte[] 로 만들어서 파일에 저장함
*Board : 인스턴스 = 객체
*인스턴스(byte[]) 를 일련의 바이트 정보로 바꾸는 것: serialize (직렬화) (=marshaling)
*byte[] : 인스턴스 필드값 + 클래스 정보(어느 클래스의 인스턴스인지)
형식별로 write 하던걸 그냥 Object로 퉁 ~
out.writeObject(board);
ObjectOutputStream으로 출력한건
ObjectInputStream클래스를 사용해서 읽어야함
파일의 byte[]을 readObject()로 읽어서 Board객체로 만들어줌
byte[]를 인스턴스로 만드는 것: deserialize (역직렬화) (=unmarshaling)
*Board : 인스턴스 = 객체
**************
this를 안 쓴다는 것: 인스턴스변수를 안 쓴다는 것. 그럼 통상 static으로 만들면 됨 .
하지만 실무에선 언젠가 인스턴스를 사용할수있으니까 그냥 논스태틱으로 (인스턴스 멤버로) 둔다.
인터페이스는 다중구현이 가능하다.
클래스는 다중상속이 안 되지만 ,,
**************
* java.io.Serializable 인터페이스
writeObject(인스턴스) 입력 --> | ObjectOutputStream | |
인스턴스: 직렬화가 허용된 클래스에 대해서만 serialize 가능 ! => 직렬화 허용 : java.io.serializable 인터페이스구현한 클래스 =>serializable : 메서드가 없다, 직렬화를 허락한다는 표시용 /버전 같이 기재 - 나중에 읽을 때 현재 내가 갖고있는 클래스의 버전과 데이터에 저장된 데이터 버전을 비교하는 용도로 사용 . public class Member implements Serializable {
private static final long serialVersionUID = 1L; *직렬화는 허락 받아야할 일인가? yes ! 객체의 내용을 그대로 외부로 내보낸다는 것은 보안을 위협하는 행위이기 때문 |
*serialVersionUID 스태틱 필드
private static final long serialVersionUID = 1L;
Member - name, email, password, gender, createdDate
wirteObject()로 출력 하면(serialize) byte[]이 파일에 저장됨 .
파일을 byte[]로 읽어서 readObject()로(deserialize) 다시 Member객체로 만듬
1번 ok
홍길동컴으로 write ( serialVersion 1) / Member - name, email, password, gender, createdDate
파일 ( serialVersion 1)
임꺽정컴으로 read ( serialVersion 1) / Member - name, email, password, gender, createdDate
2번 오류 (읽어드릴 데이터의 버전이 다름 - 못 읽음)
이전 버전으로 serialize한 데이터를 새 버전의 인스턴스로 읽어들이기 싫다면 버전 번호를 달리 하라!
홍길동컴으로 write ( serialVersion 1) / Member - name, email, password, gender, createdDate
파일 ( serialVersion 1)
임꺽정컴으로 read ( serialVersion 2) / Member - name, email, password, gender, createdDate, +postNo, +Adress +Tel
3번 ok (읽어드릴 데이터의 버전이 다름)
이전 버전으로 serialize한 데이터를 새 버전의 인스턴스로 읽어도 된다면 버전번호를 같게 하라!
홍길동컴으로 write ( serialVersion 1) / Member - name, email, password, gender, createdDate
파일 ( serialVersion 1)
임꺽정컴으로 read ( serialVersion 1) / Member - name, email, password, gender, createdDate, +postNo, +Adress +Tel
새로 추가된게 있어도 기존 내용에 추가된거니까 단순 업그레이드니까 버전 1로 그대로
CSV 형식으로 머하기
comma seprated Value,,,
텍스트포맷(csv)로 입출력하기
Board --prinf()--> prinWriter --write--> BufferedWriter --writer--> FileWriter ----> csv 파일에 저장완료!
csv 파일 : 0,0,0,0 / 0,0,0,0
csv파일 --> Filereader --> BufferedReader --read()--> String: "0,0,0,0" --split(",")--> String배열에 쪼개 넣고 --set() --> board객체에 넣음
Refactoring
1. Information Expert
App - > Board
1. board에서 get해서
2. csv 문자열을 뽑아냄 "0,0,0,0,0" <= Board 객체의 값을 가지고 csv 형식의 문자열을 생성하는 것을 App클래스가 하고있음. => Data를 갖고 있는 건 Board인데 CSV형식으로 문자열을 만드는 일을 하는 객체는 App이다.
==> Board의 필드가 추가되거나 삭제되면 App클래스를 변경해야한다.
=> Information Expert 패턴으로 전환할 필요가 있다.
:1.App이 Board에게 csv스트링 조.
2.Board가 csv 문자열을 생성한다.
3. csv 문자열을 리턴한다. 정보를 갖고있는 객체가 정보를 가공하는 일을 하도록 설계 변경! (information expert)
==> Board의 필드가 추가되거나 변경되더라도 App 클래스에는 영향을 주지 않는다.
1. 제네릭 문법: ?
private void saveCsv(String filename, List<? extends CsvObject> list)
? : csvObject의 서브 클래스거나 csvObject의 구현클래스
?에 올수 잇는거 (= list에 담을 수 있는 것, list 구현체)
: new ArrayList<Member>() ook
new LinkedList<Board>() ok
new ArrayList<String>() 안됨 => String 클래스는 CsvObject 의 서브 클래스가 아니고 CsvObject 인터페잉스를 구현하지 않아서.
CsvObject 수퍼클래스 or 인터페이스
extends 인터페이스든 수퍼클래스든 다 extends 쓰기. implements 말고~ ~
2. Factory Method (GoF) 패턴 적용
CSV 문자열 -> App 이 분석해서 -> new 객체생성 (Board or Member)
Information Expert 적용(데이터를 갖고 있고 csv 형식을 알고 있는 클래스가 인스턴스를 생성하는게 바람직하다)
CSV 문자열 -> App 이 분석해서 ->fromCsv() 객체생성 (Board or Member)
fromCsv(): 인스턴스 생성하는 메서드: 인스턴스 생성과정이 복잡할 때 인스터너스 생성코드를 캡슐화(메서드로 묶기)하는게 낫다. => Factory Method (GoF) 패턴
Reflection API를 사용하여 메서드를 찾고 호출하기 + Generic 을 사용하여 다양한 타입에 대응할 수 있는 메서드를 정의.
<T> void loadCsv(String filename, List<T> list, class<T> clazz) {
Method factoryMethod = clazz.getDeclaredMethod(""fromCsv", String.class, String.class);
(T) factoryMethod.invoke(null, line);
<T>:T가 타입 파라미터임을 선언!
Method factoryMethod : 메서드 정보를 다루는 객체
getDeclaredMethod: 현재 클래스에서 정의된 메서들 찾는다. "fromCsv" : 메서드 명 , String.class : 파라미터 타입 ,
(T) 리턴 값 형변환 / invoke : 메서드 호출 (null: 인스턴스 주소, 스태틱 메서드인 경우 null을 넘긴다. line ( 메서드를 호출할때 넘겨줄 파라미터 값)
getDeclaredMethod :
DeclaredMethod: 현재 클래스에 특정 이름을 갖는 메서드를 찾아줌, 못 찾으면 예외 발생
List: 목록을 다루는 클래스 : collection API
Method factoryMethod = clazz.getDeclaredMethod("fromCsv", String.class);
파라미터를 String class로 받는 fromCsv이름을 가진 클래스를 ,,, 찾음 ,,, factoryMethod 에 담음
Class : 메서드, 클래스, 생성자 정보를 다루는 클래스: reflection API
'[네이버클라우드] 클라우드 기반의 개발자 과정 7기 > 웹프로그래밍' 카테고리의 다른 글
[NC7기-49일차(7월4일)] - 웹프로그래밍 30일차 (0) | 2023.07.04 |
---|---|
[NC7기-48일차(7월3일)] - 웹프로그래밍 29일차 (0) | 2023.07.03 |
[NC7기-46일차(6월29일)] - 웹프로그래밍 27일차 (1) | 2023.06.29 |
[NC7기-45일차(6월28일)] - 웹프로그래밍 26일차 (0) | 2023.06.28 |
gradle cleanEclipse (0) | 2023.06.28 |