- 직렬화란 자바 시스템 내부에서 사용되는 객체 또는 데이터를 자바 외부에서도 사용할 수 있도록 바이트(byte)단위로 변환하는 것을 말한다.
- 직렬화가 가능한 자료형 및 객체
기본형 타입 (boolean, char, byte, short, int, long, float, double)
Serializable 인터페이스를 구현한 클래스의 객체
transient가 사용된 멤버변수(null 전송), static 멤버변수, 메소드는 직렬화 대상에서 제외된다.
역 직렬화(Deserialization)
- 직렬화된 바이트(byte)단위의 데이터를 다시 원래 데이터로 복원하는 것을 말한다.
java.io.Serializable 인터페이스
- 객체를 직렬화하기 위해서는 먼저, 객체를 직렬화가 가능하도록 Serializable 인터페이스를 구현해야 한다.
- 이 인터페이스는 객체 직렬화가 제공되어야 함을 자바 가상 머신에 알려주는 역할을 한다.
- Serializable 인터페이스는 다른 인터페이스와는 달리 구현해야 할 메소드가 없으므로 단지 Serializable 인터페이스만 implements 하면 된다.
- 객체의 직렬화 대상에서 제외되는 것은 멤버 변수가 static으로 선언된 경우, 멤버 변수가 transient로 선언된 경우와 메소드이다.
형식
public class 클래스명 implements Serializable {
// 클래스 정의 부분
}
transient
- 직렬화 대상에서 제외할 멤버 변수는 transient 키워드를 사용하여 제외한다.
- transient 키워드가 붙은 멤버 변수가 복원되면, 숫자변수는 0, 객체는 null로 설정된다.
public class 클래스명 implementsSerializable{
접근제어자 자료형 변수1;
접근제어자 transient 자료형 변수2;
// 클래스 구현
}
SerialVersionUID 필드
- serialVersionUID 는 직렬화에 사용되는 고유 아이디로, 선언하지 않으면 JVM에서 디폴트로 자동생성된다.
serialVersionUID는 역 직렬화 해서 읽어 들일 때 캐스팅한 클래스의 serialVersionUID와 역직렬화 한 serialVersionUID가 맞는지 확인하기 위해 사용된다.
- 선언하지 않아도 동작하는데 문제는 없지만, JVM에 의한 디폴트 serialVersionUID 계산은 클래스의 세부 사항을 매우 민감하게 반영하기 때문에 컴파일러 구현체에 따라서 달라질 수 있어 역 직렬화(deserialization) 과정에서 예상하지 못한 InvalidClassException을 유발할 수 있다.
- Java에서는 명시적으로 serialVersionUID를 선언할 것을 적극 권장하고 있다.
- 기본 Java 데이터 유형을 플랫폼에 독립적인 방법으로 기본 입력 스트림에서 읽을 수 있다.
- 필터 스트림이기 때문에 다른 입력 스트림을 생성자의 인자로 받아 객체를 생성한다.
- InputStream, FilterInputStream의 하위 클래스
import java.io.DataInputStream;
import java.io.FileInputStream;
public class Ex016_DataInputStream {
public static void main(String[] args) {
// DataOutputStream으로 저장한 내용은 DataInputStream으로 읽어야 한다.
// 저장한 자료형 순서대로 읽어 들인다.
// 더 이상 읽을 데이터가 없으면 IOException이 발생된다.
try(DataInputStream dis = new DataInputStream(new FileInputStream("text.txt"))) {
System.out.println(dis.readUTF());
System.out.println(dis.readByte());
System.out.println(dis.readChar());
System.out.println(dis.readInt());
System.out.println(dis.readInt());
System.out.println(dis.readUTF());
} catch (Exception e) {
e.printStackTrace();
}
}
}
java.io.DataOutputStream 클래스
- 기본 Java 데이터 유형을 출력하는 기능을 가진 클래스로 필터 스트림이기 때문에 다른 출력 스트림을 생성자의 인자로 받아 생성한다.
- OutputStream, FilterOutputStream의 하위 클래스
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Ex015_DataOutputStream {
public static void main(String[] args) {
try(DataOutputStream dos = new DataOutputStream(new FileOutputStream("text.txt"))) {
dos.writeUTF("서울");
dos.writeByte(10);
dos.writeChar('A');
dos.writeInt(50);
dos.writeInt(70);
dos.writeUTF("서울");
System.out.println("파일 저장 완료...");
} catch (IOException e) {
e.printStackTrace();
}
}
}
필터 스트림 ?
- 필터 스트림은 기존의 스트림을 원하는 기능을 제공하는 새로운 스트림으로 바꾸어 주는 스트림이다.
- 필터 스트림의 최상위 클래스에는 FilterInputStream과 FilterOutputStream클래스가 있다.
FilterInputStream과 FilterOutputStream 클래스
- 이 클래스를 인스턴스 한 객체는 매개변수로 입력 받은 다른 스트림과 연결되어있다.
- 실제 데이터 소스에서 스트림을 처리하는 것이 아니라 다른 스트림과 연결하는 용도로 사용된다.
따라서 입/출력 스트림에서 받은 데이터를 다른 데이터로 변환하거나 추가 작업을 하는 클래스이다.
- user.txt 파일을 읽어서 합격자만 pass.txt에 저장하는 프로그램 작성 - user.txt 파일 형식 이름,국,영,수 - pass.txt 파일 형식 이름,국,영,수 - 세과목 모두 40점 이상이고 평균이 60점 이상인 경우만 합격자 - pass.txt에 저장할 때는 총점 내림차순으로 저장(단, 이것은 못하겠으면 안해도 됨) - UserDTO 만들고, UserPass 라는 클래스를 만들어서 작성할 것 - ArrayList 사용하면 쉽다. (Map 사용 안함) - 작성할 수 있는데 까지 작성해서 메일로 보내기
Main
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
public class Ex012_PassUser {
public static void main(String[] args) {
UserPass vo = new UserPass();
vo.loadfile();
vo.savefile();
System.out.println("파일 생성 완료...");
}
}
Class
class UserDTO {
private String name;
private Integer kor;
private Integer eng;
private Integer mat;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getKor() {
return kor;
}
public void setKor(Integer kor) {
this.kor = kor;
}
public Integer getEng() {
return eng;
}
public void setEng(Integer eng) {
this.eng = eng;
}
public Integer getMat() {
return mat;
}
public void setMat(Integer mat) {
this.mat = mat;
}
}
class UserPass {
private ArrayList<UserDTO> list = new ArrayList<>();
private String pathname1 = "user.txt";
private String pathname2 = "pass.txt";
public void loadfile() {
try(BufferedReader br = new BufferedReader(new FileReader(pathname1))) {
String s;
while ( (s = br.readLine()) != null ) {
String [] ss = s.split(",");
if(ss.length < 2) {
continue;
}
UserDTO vo = new UserDTO();
vo.setName(ss[0]);
int kor, eng, mat, tot;
long ave;
kor = Integer.parseInt(ss[1]);
eng = Integer.parseInt(ss[2]);
mat = Integer.parseInt(ss[3]);
tot = kor+eng+mat;
ave = tot / 3 ;
if ( ave >=60 && (kor>=40 && eng>=40 && mat >=40)) {
vo.setKor(kor);
vo.setEng(eng);
vo.setMat(mat);
list.add(vo);
} else {
continue;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void savefile() {
try(PrintStream ps = new PrintStream(pathname2)) {
Iterator<UserDTO> it = list.iterator();
while(it.hasNext()) {
UserDTO vo = it.next();
ps.println(vo.getName()+"\t"+vo.getKor()+"\t"
+vo.getEng()+"\t"+vo.getMat());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
총점 내림차순은
혼자서 해보다가 못했음.
내가 하려고 했던 방법은,
1) int[] 를 만들어서 총점을 담는다.
2) list.add 할 때 만 총점 배열에 총점을 넣음. 그래야 출력(합격자)할 자료들만 모아지니까
3) list.add 가 끝나면 그 배열을 선택정렬을 통해 정렬할때 리스트도 list.set() 으로 바꿈.
int [] total = new int[] {list.size()};
int count = 0;
total[count++] = tot;
UserDTO vo2;
int c;
for (int i = 0; i<list.size() -1 ; i++){
for(int j = i+1; i<list.size() ; j++){
if(total[i] < total[j]){
c = total[i];
total[i] = total[j];
total[j] = c;
vo2 = list.get(i);
list.set(i, list.get(j));
list.set(j, vo2);
}
}
}
원래 합격자들만 출력한 결과는
이것인데 총점 내림차순은 못했음.
public void loadfile() {
int [] total = new int[] {list.size()};
try(BufferedReader br = new BufferedReader(new FileReader(pathname1))) {
String s;
while ( (s = br.readLine()) != null ) {
String [] ss = s.split(",");
if(ss.length < 2) {
continue;
}
UserDTO vo = new UserDTO();
vo.setName(ss[0]);
int kor, eng, mat, tot;
long ave;
kor = Integer.parseInt(ss[1]);
eng = Integer.parseInt(ss[2]);
mat = Integer.parseInt(ss[3]);
tot = kor+eng+mat;
ave = tot / 3 ;
if ( ave >=60 && (kor>=40 && eng>=40 && mat >=40)) {
vo.setKor(kor);
vo.setEng(eng);
vo.setMat(mat);
list.add(vo);
int count = 0;
total[count++] = tot;
} else {
continue;
}
UserDTO vo2;
int c;
for (int i = 0; i<total.length-1 ; i++){
for(int j = i+1; i<total.length ; j++){
if(total[i] < total[j]){
c = total[i];
total[i] = total[j];
total[j] = c;
vo2 = list.get(i);
list.set(i, list.get(j));
list.set(j, vo2);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
이렇게 하니까 안터지긴 하는데 결과가 정렬부분 있든 없든 똑같음...
그럼
아예 UserDTO 에 총점입력하는 칸을 넣어서 하는 것이 어떨까?
public class Ex012_PassUser {
public static void main(String[] args) {
UserPass vo = new UserPass();
vo.loadfile();
vo.sort();
vo.savefile();
System.out.println("파일 생성 완료...");
}
}
class UserDTO {
private String name;
private Integer kor;
private Integer eng;
private Integer mat;
private Integer tot;
public Integer getTot() {
return tot;
}
public void setTot(Integer tot) {
this.tot = tot;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getKor() {
return kor;
}
public void setKor(Integer kor) {
this.kor = kor;
}
public Integer getEng() {
return eng;
}
public void setEng(Integer eng) {
this.eng = eng;
}
public Integer getMat() {
return mat;
}
public void setMat(Integer mat) {
this.mat = mat;
}
}
class UserPass {
private ArrayList<UserDTO> list = new ArrayList<>();
private String pathname1 = "user.txt";
private String pathname2 = "pass.txt";
public void loadfile() {
try (BufferedReader br = new BufferedReader(new FileReader(pathname1))) {
String s;
while ((s = br.readLine()) != null) {
String[] ss = s.split(",");
if (ss.length < 2) {
continue;
}
UserDTO vo = new UserDTO();
vo.setName(ss[0]);
int kor, eng, mat, tot;
long ave;
kor = Integer.parseInt(ss[1]);
eng = Integer.parseInt(ss[2]);
mat = Integer.parseInt(ss[3]);
tot = kor + eng + mat;
ave = tot / 3;
if (ave >= 60 && (kor >= 40 && eng >= 40 && mat >= 40)) {
vo.setKor(kor);
vo.setEng(eng);
vo.setMat(mat);
vo.setTot(tot);
list.add(vo);
} else {
continue;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void savefile() {
try (PrintStream ps = new PrintStream(pathname2)) {
Iterator<UserDTO> it = list.iterator();
while (it.hasNext()) {
UserDTO vo = it.next();
ps.println(vo.getName() + "\t" + vo.getKor()
+ "\t" + vo.getEng() + "\t" + vo.getMat());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void sort() {
UserDTO vo2;
for (int i = 0; i < list.size() - 1; i++) {
for (int j = i + 1; j < list.size(); j++) {
if(list.get(i).getTot() < list.get(j).getTot()) {
vo2 = list.get(i);
list.set(i, list.get(j));
list.set(j, vo2);
}
}
}
}
}
예!! 이렇게 정렬하는 것을 따로 메소드로 만들어서 거기서 총점을 가지고 바꾸는 것을 해보았다.
예! 총점은 확인용으로 출력해보았다.
앗싸 - 이게 맞는지는 내일 수업을 듣고 업데이트 하겠다.
총점 내림 차순 추가
Main
public class Ex012_PassUser {
public static void main(String[] args) {
UserPass vo = new UserPass();
vo.loadfile();
vo.sort();
vo.savefile();
System.out.println("파일 생성 완료...");
}
}
Class
class UserDTO {
private String name;
private Integer kor;
private Integer eng;
private Integer mat;
private Integer tot;
public Integer getTot() {
return tot;
}
public void setTot(Integer tot) {
this.tot = tot;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getKor() {
return kor;
}
public void setKor(Integer kor) {
this.kor = kor;
}
public Integer getEng() {
return eng;
}
public void setEng(Integer eng) {
this.eng = eng;
}
public Integer getMat() {
return mat;
}
public void setMat(Integer mat) {
this.mat = mat;
}
}
class UserPass {
private ArrayList<UserDTO> list = new ArrayList<>();
private String pathname1 = "user.txt";
private String pathname2 = "pass.txt";
public void loadfile() {
try (BufferedReader br = new BufferedReader(new FileReader(pathname1))) {
String s;
while ((s = br.readLine()) != null) {
String[] ss = s.split(",");
if (ss.length < 2) {
continue;
}
UserDTO vo = new UserDTO();
vo.setName(ss[0]);
int kor, eng, mat, tot;
double ave;
kor = Integer.parseInt(ss[1]);
eng = Integer.parseInt(ss[2]);
mat = Integer.parseInt(ss[3]);
tot = kor + eng + mat;
ave = tot / 3;
if (ave >= 60 && (kor >= 40 && eng >= 40 && mat >= 40)) {
vo.setKor(kor);
vo.setEng(eng);
vo.setMat(mat);
vo.setTot(tot);
list.add(vo);
} else {
continue;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void savefile() {
try (PrintStream ps = new PrintStream(pathname2)) {
Iterator<UserDTO> it = list.iterator();
while (it.hasNext()) {
UserDTO vo = it.next();
ps.println(vo.getName() + "\t" + vo.getKor()
+ "\t" + vo.getEng() + "\t" + vo.getMat());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void sort() {
UserDTO vo2;
for (int i = 0; i < list.size() - 1; i++) {
for (int j = i + 1; j < list.size(); j++) {
if(list.get(i).getTot() < list.get(j).getTot()) {
vo2 = list.get(i);
list.set(i, list.get(j));
list.set(j, vo2);
}
}
}
}
}