오늘 배운 문법 정리 ✍
다형성(Polymorphism) 이란❓
: 다형성이란 부모-자식 상속 관계에 있는 클래스에서 상위 클래스가 동일한 메시지로
하위 클래스들을 서로 다르게 동작시키는 객체 지향 원리이다. 다형성을 활용하면
부모 클래스가 자식 클래스의 동작 방식을 알 수 없어도 오버라이딩을 통해 자식
클래스로 접근할 수 있다.
: 다형성은 여러 객체를 하나의 타입으로 관리가 가능하기 때문에, 코드 관리가 편리해
유지보수가 용이하고, 객체를 재사용하기가 쉬워진다는 장점이 있다.
제네릭(Generics) 이란❓
: 컴파일 시 타입을 체크해주는 기능으로 객체의 타입 안정성을 높이고, 형변환의
번거로움을 줄여준다. 따라서 타입 안정성을 높여주고, 타입 확인과 형변환을 생략할 수
있어 코드가 간결해 진다.
문법) List<String
> list = new ArrayList<String
>( );
public class GenericMain {
public static void main(String[] args) {
Parents<String> parentsString = new Parents<String>("제네릭");
Parents<Character> parentsChar = new Parents<Character>('c');
Parents<Integer> parentsInt = new Parents<Integer>(100);
// 제네릭을 사용하지 않은 리스트
List integerList1 = new ArrayList();
integerList1.add("글자");
integerList1.add(100);
// 제네릭으로 타입을 Integer로 설정한 리스트
List<Integer> integerList2 = new ArrayList<Integer>();
//integerList2.add("글자"); // 제네릭으로 문자열 타입 저장 불가
integerList2.add(100);
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(0, "값1");
}
}
스트림(Stream) 이란❓
: 프로그램은 외부에서 데이터를 읽거나 외부로 데이터를 출력하는 작업이 빈번하게
발생하고, 데이터는 통로를 통해서 이동하는데 이 통로를 스트림이라고 한다.
즉, 데이터를 운반(입/출력) 하는데 사용되는 연결통로를 말한다.
: 흔히, 우리가 파일을 닫을 때 "해당 파일은 다른 프로그램이 사용중이라 삭제할 수 없다"
라는 경고 메시지를 본적이 있을 것이다. 바로 이것이 스트림이 열려있기 때문에 파일을
닫을 수 없는 것이었다.
: 스트림의 종류 ( 수업 중 사용한 것만 정리 ✅ )
1) 바이트 기반 스트림 : InputStream
/ OutputStream
2) 보조 스트림(스트림의 기능 향상) : BufferedInputStream
/ BufferedOutputStream
3) 문자 기반의 파일 입출력 스트림 : FileReader
/ FileWriter
4) 파일에 데이터를 입출력하는 바이트기반 스트림 :
FileInputStream
/ FileOutputStream
5) 데이터를 다양한 형식의 문자로 출력하는 기능 제공 스트림 : PrintStream
import java.io.*;
public class StreamMain3 {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream=null;
FileOutputStream fileOutputStream=null;
try {
// 텍스트 파일 복사
fileInputStream = new FileInputStream("c:\\test\\test01.txt");
fileOutputStream = new FileOutputStream("c:\\test\\test02.txt");
// 그림 파일 복사
FileInputStream fileInputStream = new FileInputStream("c:\\test\\pic01.png");
FileOutputStream fileOutputStream = new FileOutputStream("c:\\test\\pic02.png");
byte[] bytes = fileInputStream.readAllBytes();
for(int i=0; i<bytes.length; i++) {
fileOutputStream.write(bytes[i]);
}
// 텍스트 파일 내용 출력 (바이트 단위로 읽기 때문에 한글은 깨진다.)
int data = 0;
while ((data = fileInputStream.read()) != -1) {
System.out.print((char)data);
}
// 만약, 글자 단위로 읽고 싶다면? FileReader 스트림 사용
fileInputStream = new FileInputStream("c:\\test\\test01.txt");
fileOutputStream = new FileOutputStream("c:\\test\\test02.txt");
int data = 0;
while ((data = fileReader.read()) != -1) {
System.out.print((char)data);
}
} catch (FileNotFoundException e) {
System.out.println("그런 파일 없음");
} catch (IOException e) {
System.out.println("읽을 수 없음");
} finally {
if(fileInputStream != null) {
fileInputStream.close(); // 스트림을 열었으면 무조건 닫아줘야 한다.
}
if(fileOutputStream != null) {
fileOutputStream.close(); // 스트림을 열었으면 무조건 닫아줘야 한다.
}
}
}
}
🙉 스트림을 사용하여 네트워크 프로그래밍 실습하기 🙉
package day06;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
// 서버 클래스
public class ServerTest {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(7777);
Socket yhd = serverSocket.accept();
System.out.println(yhd.getInetAddress() + " 주소를 사용하는 고객이 접속하였습니다.");
// 여기서부터 보내는 코드
System.out.print("고객에게 보낼 메시지를 입력하세요 : ");
Scanner sc = new Scanner(System.in);
OutputStream cos = yhd.getOutputStream();
PrintStream ps = new PrintStream(cos);
String test1 = sc.nextLine();
ps.println(test1);
// 여기까지 보내는 코드
System.out.println();
// 여기서부터 받는 코드
System.out.print("고객이 서버로 보낸 메시지입니다 : ");
InputStream cis = yhd.getInputStream();
InputStreamReader isr = new InputStreamReader(cis);
BufferedReader br = new BufferedReader(isr);
String str = br.readLine();
System.out.println(str);
// 여기까지 받는 코드
serverSocket.close();
yhd.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
// 클라이언트 클래스
public class ClientTest {
public static void main(String[] args) {
try {
Socket yhd = new Socket("192.168.0.114", 7777);
System.out.print("서버에서 보낸 메시지입니다 : ");
InputStream cis = yhd.getInputStream();
InputStreamReader isr = new InputStreamReader(cis);
BufferedReader br = new BufferedReader(isr);
String str = br.readLine();
System.out.println(str);
System.out.print("서버에 요청할 메시지를 입력하세요 : ");
Scanner sc = new Scanner(System.in);
OutputStream cos = yhd.getOutputStream();
PrintStream ps = new PrintStream(cos);
String test2 = sc.nextLine();
ps.println(test2);
yhd.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
package day06;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.io.FileInputStream;
import java.io.FileOutputStream;
// 서버 클래스
public class ServerFileTest {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(9999);
Socket yhd = serverSocket.accept();
System.out.println(yhd.getInetAddress() + " 주소를 사용하는 고객이 접속하였습니다.");
// 여기서부터 받는 코드
System.out.print("고객이 서버로 보낸 메시지입니다 : ");
InputStream cis = yhd.getInputStream();
InputStreamReader isr = new InputStreamReader(cis);
BufferedReader br = new BufferedReader(isr);
String str = br.readLine(); // str : 고객이 입력한 파일명
System.out.println(str);
// 여기까지 받는 코드
System.out.println();
// 여기서부터 보내는 코드
FileInputStream fileInputStream = new FileInputStream("c:\\test\\" + str);
BufferedOutputStream brs = new BufferedOutputStream(yhd.getOutputStream());
byte[] bytes = fileInputStream.readAllBytes();
for(int i=0; i<bytes.length; i++) {
brs.write(bytes[i]);
System.out.print((char)bytes[i]);
}
// 여기까지 보내는 코드
brs.close();
serverSocket.close();
yhd.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
// 클라이언트 클래스
public class ClientFileTest {
public static void main(String[] args) {
try {
Socket yhd = new Socket("192.168.88.1", 9999);
// 여기부터 요청하는 코드
System.out.print("서버에 요청할 메시지를 입력하세요 : ");
Scanner sc = new Scanner(System.in);
OutputStream cos = yhd.getOutputStream();
PrintStream ps = new PrintStream(cos);
String test2 = sc.nextLine();
ps.println(test2);
// 여기까지 요청하는 코드
// 여기부터 요청받는 코드
InputStream cis = yhd.getInputStream();
BufferedInputStream brs = new BufferedInputStream(cis);
FileOutputStream fileOutputStream = new FileOutputStream("c:\\test2\\" + test2);
byte[] bytes = brs.readAllBytes();
for(int i=0; i<bytes.length; i++) {
fileOutputStream.write(bytes[i]);
}
// 여기까지 요청받는 코드
System.out.print("요청이 이뤄졌습니다.");
yhd.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
코드 실행 결과 : C 드라이브 안에 test 폴더에 있는 test01.txt 파일을 클라이언트가 서버로 요청하면 서버에서 해당 파일을 C 드라이브 안에 test2 폴더에 생성시켜준다.
실습 간 알게 된 사실🧐
brs.close()'
이BufferedOutputStream
으로 넘겨줬는데, 이 스트림을 닫아주지 않아서 파일이 넘어갈때 내용이 저장되지 않고 넘어간 것이 아닌가 추측된다.오늘의 느낀점 👀
오늘 배운 것 중 가장 중요했던 것은 스트림의 이해였던 것 같다. 특히나, 네트워크에 연결하여 서로 데이터를 주고 받는 입/출력에 대해서 실습을 해봤는데, 강사님께서 강조하신게 "소켓 통신이 뭔가요?" 라는 질문에 "채팅 프로그램" 이라는 답변을
학생들이 많이 한다고 한다.
하지만 이것은 전혀 잘못된 답변이고, 정확히 이해를 못한채로 그냥 사용하는 것이라고 하셨다. 결국에 소켓 프로그램은 네트워크 프로그램을 말하는 것이다. 따라서 소켓 통신은 글자 뿐만 아니라, 파일, 화면, 데이터 베이스 등 다양한 유형을 입/출력 할 수 있도록 해준다.
드디어, 오늘은 네트워크 연결을 프로그래밍으로 간단하게나마 구현해 본 시간이었다. DB 수업때 DB 서버에 연결할때는 리눅스에서 IP 주소를 입력하여 연결했었는데, 방식은 크게 다르지 않았던것 같다. 중요한건, 입/출력 받는 데이터의 형식에 따라 사용하는 스트림의 종류가 다를 수 있다는 점인 것 같다.
이번주는 토요일에 있는 빅데이터 분석기사 실기시험 준비로 프로그래머스는 못풀것 같다. 못한부분은 무사히 시험을 끝내고 다시 시작하려 한다. 수업 시간 중에 틈틈히 풀어보고 있는데, 풀은 문제들은 시험 종료 후 한번에 정리할 예정이다.