2013년 1월 28일 월요일
[Java] 프로젝트 스샷과 코드
왼쪽에 가장 큰 화면이 Client에서 접속한 화면이다.
식당의 테이블에서 손님에게 보여지는 화면으로써 원격으로 메뉴를 선택하고 주문할 수 있다. 추천기능도 있고 음식이 요리되는 동안 지루함을 덜기 위한 게임도 마련했다.
네트워크를 담당하여 Client와 Server가 연동되도록 하는 부분을 맡았기 때문에 서버에 대해 설명하자면 클라이언트에서 프로그램을 실행시키는 즉시 서버에 접속한다.
그러면 바로 서버에서 몇번 테이블에 손님이 왔는지 바로 확인이 가능하며 주문을 받고 손님의 요구사항도 채팅창을 통해 알 수 있다. 주문서를 확인하여 주문확인 버튼을 클릭함으로써 손님에게 메세지를 전송할 수 있고 마찬가지로 요리완료 메세지도 전달할 수 있다.
초기에 목표로 했던 부분들은 다 완성시킨 프로젝트이다.
나름 중요한 코드만 올리고 끝.
서버
try {
serverSocket = new ServerSocket(9000);
while (true) {
socket = serverSocket.accept();// 클라이언트의 소켓을 기다리다가 클라이언트가 접속하면 클라이언트의 소켓을 얻음
ServerFrame sf = new ServerFrame(socket);//접속과 동시에 서버에서 보이는 테이블창 생성
Thread t = new Thread(sf);//스레드 작동. 그 이유는 해당하는 테이블의 클라이언트가 접속을 종료하면 그것을 확인하여 자동으로 종료하기 위함
t.start();
}
} catch (Exception e) {
} finally {
try {// 서버 종료
socket.close();
serverSocket.close();
} catch (Exception e) {
}
서버접속후 각각의 손님 테이블을 돌리는 스레드(제일 중요)
public void run() {
try {
ta.append(name + " 손님이 오셨습니다." + "\n");
ta.setSelectionStart(ta.getText().length());
while (true) {
String str = br.readLine();
if (str.equals("#주문")) {//읽어들이는 문자열 중 "#주문" 이라는 문자열이 왔을 때 주문에 관련된 문자열처리
ta.append(name + ">" + "주문들어왔습니다." + "\n");
ta.setSelectionStart(ta.getText().length());
if (map.containsKey(name)) {
map.remove(name);
}
String str1 = br.readLine();
stk = new StringTokenizer(str1, ",");//문자열 나누기
alist = new ArrayList<String>();
while (stk.hasMoreTokens()) {
alist.add(stk.nextToken());
}
map.put(name, alist);
continue;
} else if (str.equals("#호출")) {//"#호출"이라는 문자열이 들어왔을 때 호출 창 띄우기
new ServerCall(name + "에서 긴급 호출입니다!");
}
ta.append(name + ">" + str + "\r\n");
ta.setSelectionStart(ta.getText().length());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
ta.append(name + ">" + "퇴실하셨습니다");
ta.setSelectionStart(ta.getText().length());
new ServerFrameClose(name + ">" + "퇴실하셨습니다", f);
try {
br.close();
pw.close();
socket.close();
notify();
} catch (Exception e) {
}
}
}
2013년 1월 27일 일요일
[Java] 자바 프로젝트
프로젝트를 진행하면서 가장 먼저 기본적인 틀이 중요하다고 생각했다. 아이디어회의를 통해 생각한 기능과 UI를 조잡스럽지만 빠르게 기본골격을 갖추고 진행한 것이 마무리하는 날까지 많은 도움이 되었다.
두 번째는 기능과 기능의 연관관계를 어떻게 세우는가이다. 사실 이부분이 처음엔 제일 막막했다. 실제 구현가능한 범위와 배웠던 부분을 활용하여 하나씩해나가긴 했지만 처음에 클래스를 어떻게 만들어 서로 연계시킬지, 또는 객체지향적인 측면을 살려 상속은 어떻게 할지 등 많은 고민이 있었다. 경험은 적은데 많은 것을 하려다보니 어려웠던것 같다. 하지만 잘 정리해둔 프로그램의 흐름을 완성시키면 코딩은 그렇게 어렵지 않았다. 따라서 클래스 디자인이 왜 중요한지 제대로 경험한 프로젝트였다.
세 번째는 네트워크와 관련해서 데이터를 어떤식으로 주고 받을지 많이 고민하였다. 소켓을 이용하여 데이터를 주고받는 것은 알았지만 스트림은 결국 하나만 존재하고 그 스트림에 다가 다양한 필터스트림을 연결시켰다 해제하는 것은 나로선 어려웠다. 그렇다면 객체의 정보는 어떻게 넘길것인가 고민하다가 결국 문자열을 효율적으로 다루기로 했다. 무엇이 일반 문자열이고 무엇이 주문내역서를 위한 데이터인지 구별해 주는 방향으로 가닥을 잡았다.
다행이 생각대로 문자를 처리해 주는 것이 성공!
마지막단계에 발전된 GUI와 완성된 기능을 합치고 에러를 잡아가는 과정이 길었다. 하지만 점점 코드를 보면서 정리하는 것이 재미있었다. 무엇이든지 계속 고치고 고치면 점점 나아지는 것같다.
내일이 발표라 코드와 스크린샷은 다음에 올리도록 하겠다.
2013년 1월 22일 화요일
[Java] Event 처리
프레임을 띄워서 보여지기만 하고 아무 기능을 하지 못하면 프로그램이 아니다.
버튼을 누르면 해당하는 기능이 실행되거나 텍스트필드에 글을 입력해서 처리하거나 하는 일들이 남아 있다.
사용자가 사용하면서 입력을 할때마다 어떠한 액션(Action)을 취하게 되는데 그때마다 이벤트가 생기게 된다. 이러한 이벤트들을 적절히 처리해 주면 되는 것이다.
그 흐름을 살펴보자.
첫번째 이벤트가 생기려면 이벤트 소스들(버튼 등)이 필요하다. 즉 이벤트의 대상이 필요한데 이러한 작업은 앞서 살펴봤듯이 프레임을 만들면서 구성해주면 된다.
두번째 이벤트가 발생하면 그 이벤트를 처리해야할 객체가 필요하다. 일단 코드를 보면
b.addActionListener(객체);
b라는 버튼 객체에다 addActionListener();메소드를 호출하면서 객체를 전달하고 있다. 객체는 무조건 ActionListener라는 인터페이스를 구현해 놓고 있어야만 버튼이 눌러졌을 때 이벤트를 받아 처리 할 수 있다.
ActionListener는 인터페이스이기 때문에 무조건 메소드를 오버라이딩 한다는 것은 당연하다. 이 안에 actionPerformed라는 메소드를 오버라이딩하면 버튼으로부터 생겨난 이벤트를 이 메소드가 처리해 주게 된다.
버튼을 누르면 해당하는 기능이 실행되거나 텍스트필드에 글을 입력해서 처리하거나 하는 일들이 남아 있다.
사용자가 사용하면서 입력을 할때마다 어떠한 액션(Action)을 취하게 되는데 그때마다 이벤트가 생기게 된다. 이러한 이벤트들을 적절히 처리해 주면 되는 것이다.
그 흐름을 살펴보자.
첫번째 이벤트가 생기려면 이벤트 소스들(버튼 등)이 필요하다. 즉 이벤트의 대상이 필요한데 이러한 작업은 앞서 살펴봤듯이 프레임을 만들면서 구성해주면 된다.
두번째 이벤트가 발생하면 그 이벤트를 처리해야할 객체가 필요하다. 일단 코드를 보면
b.addActionListener(객체);
b라는 버튼 객체에다 addActionListener();메소드를 호출하면서 객체를 전달하고 있다. 객체는 무조건 ActionListener라는 인터페이스를 구현해 놓고 있어야만 버튼이 눌러졌을 때 이벤트를 받아 처리 할 수 있다.
ActionListener는 인터페이스이기 때문에 무조건 메소드를 오버라이딩 한다는 것은 당연하다. 이 안에 actionPerformed라는 메소드를 오버라이딩하면 버튼으로부터 생겨난 이벤트를 이 메소드가 처리해 주게 된다.
[Java] GUI기반 프로그래밍
자바에서는 GUI기반 프로그래밍 기법도 제공한다. 그러나 그리 흔히 쓰이지는 않는다고 한다. 그렇지만 그래픽기반 프로그래밍을 통해 느낄 수 있는 것들이 실제로 많이 있다. 예를 들어 어떻게 레이아웃을 구성하고 어떻게 이벤트를 처리해줘야 할지 등등이다. 이러한 것들을 알고 있어야 윈도우나 다른 OS기반의 GUI프로그래밍을 하는데 어려움이 없을 것이다.
자바에는 AWT, Swing 그리고 Applet 이라는 클래스들을 제공하고 있다. 이 클래스들을 활용하여 제작해보자.
.JPG)
첫번째로 알고 있어야 하는 개념은 container 개념이다. 버튼이나 라벨, 텍스트필드와 같은 구성요소(Component)들이 container위에 얻어지게 되기 때문이다.
따라서 제일 먼저 Frame이라는 윈도우 프레임을 준비해야 한다. 그 위에 Panel이라는 판을 놓게 된다. Panel을 Frame위에 올리기 전 각각의 다양한 Component들을 Panel에 원하는 방법과 디자인으로 구성해 주어야한다.
프레임 생성부터 살펴보자
Frame f = new Frame("자바");
프레임제작. 그냥 객체 생성에 불과하다.. 인자로 넣은 문자열은 프로그램 탭에 표시된다.
Panel과 다른 Component들도 다 이런식이다.
이렇게 만들어진 Componet들은 Panel에 붙이고 Panel은 Frame에 붙이면 끝. add란 메소드 호출하면 끝이다.
Button b = new Button();
panel.add(b);
이렇게 모든 준비가 끝나면 Frame을 화면에 띄워야 한다.
f.setVisible(true);
그럼 끝.
레이아웃을 변경하기도 하고 프레임의 사이즈나 보여지는 위치를 지정하는 메소드들은 다양하다. 그러한 내용은 금방 찾아서 참고할 수 있으니 생략한다.
자바에는 AWT, Swing 그리고 Applet 이라는 클래스들을 제공하고 있다. 이 클래스들을 활용하여 제작해보자.
첫번째로 알고 있어야 하는 개념은 container 개념이다. 버튼이나 라벨, 텍스트필드와 같은 구성요소(Component)들이 container위에 얻어지게 되기 때문이다.
따라서 제일 먼저 Frame이라는 윈도우 프레임을 준비해야 한다. 그 위에 Panel이라는 판을 놓게 된다. Panel을 Frame위에 올리기 전 각각의 다양한 Component들을 Panel에 원하는 방법과 디자인으로 구성해 주어야한다.
프레임 생성부터 살펴보자
Frame f = new Frame("자바");
프레임제작. 그냥 객체 생성에 불과하다.. 인자로 넣은 문자열은 프로그램 탭에 표시된다.
Panel과 다른 Component들도 다 이런식이다.
이렇게 만들어진 Componet들은 Panel에 붙이고 Panel은 Frame에 붙이면 끝. add란 메소드 호출하면 끝이다.
Button b = new Button();
panel.add(b);
이렇게 모든 준비가 끝나면 Frame을 화면에 띄워야 한다.
f.setVisible(true);
그럼 끝.
레이아웃을 변경하기도 하고 프레임의 사이즈나 보여지는 위치를 지정하는 메소드들은 다양하다. 그러한 내용은 금방 찾아서 참고할 수 있으니 생략한다.
2013년 1월 21일 월요일
[Java] 채팅방
코드는 시간이 될 때 적어보기로 하고 일단 어떤 방식으로 채팅방이 돌아가는지 이해하는 것이 더 중요하다고 생각한다.
서버에서 계속 클라이언트들의 소켓을 기다린다.
클라이언트의 연결이 되고 클라이언트 소켓을 얻으면 하나의 스레드로 만들어 주고 다른 클라이언트를 계속 기다리는 것이다.
연결이 된 클라이언트는 서버에 메세지를 보내게 될 것이고 서버는 읽어들인 메세지를 연결되어 있는 모든 클라이언트들에게 다시 전송시킴으로써 채팅이 가능하다.
즉, 서버를 다리로 각각의 클라이언트들이 연결되는 것이다.
따라서 서버에서 메세지를 적절히 처리해 주는 것이 필요하다. 어려운 내용은 아니다. 이해가 안되는 것은 아니지만 입출력의 이해 뿐만 아니라 서버에 접속해 있는 클라이언트들을 관리하는 것이 필요하다.
서버에서 계속 클라이언트들의 소켓을 기다린다.
클라이언트의 연결이 되고 클라이언트 소켓을 얻으면 하나의 스레드로 만들어 주고 다른 클라이언트를 계속 기다리는 것이다.
연결이 된 클라이언트는 서버에 메세지를 보내게 될 것이고 서버는 읽어들인 메세지를 연결되어 있는 모든 클라이언트들에게 다시 전송시킴으로써 채팅이 가능하다.
즉, 서버를 다리로 각각의 클라이언트들이 연결되는 것이다.
따라서 서버에서 메세지를 적절히 처리해 주는 것이 필요하다. 어려운 내용은 아니다. 이해가 안되는 것은 아니지만 입출력의 이해 뿐만 아니라 서버에 접속해 있는 클라이언트들을 관리하는 것이 필요하다.
[Java] 서버와 클라이언트 메세지 1대1 주고 받기
서버와 클라이언트간에 메세지를 주고 받으려면 입력과 출력에 대한 기본적인 지식을 상기시킬 필요가 있겠다.
그 이유는 클라이언트가 키보드로부터 메세지를 출력스트림으로 전달 할 것이고 서버에서 메세지를 읽기 위해 입력스트림을 연결해야 하기 때문이다. 또한 서버에서 클라이언트로 메세지를 보내는 것도 같은 이치이다.
그렇다면 출력과 입력을 위한 스트림을 얻어와야 하는데 이를 위해 소켓이 필요하다.
데이터를 수신하기 위한 입력스트림을 얻는 방법은
InputStream in = socket.getInputStream();
데이터를 송신하기 위한 출력스트림 얻는 방법
OutputStream out = socket.getOutputStream();
---------------------------------------------------------------------------------
Server 측에서 할일
서버소켓준비, 클라이언트 소켓 대기, Sender와 Receiver 스레드로 입출력 처리
Client 측에서 할일
서버연결, Sender와 Receiver 스레드로 입출력 처리
코드는 길어서 공개는 생략
그 이유는 클라이언트가 키보드로부터 메세지를 출력스트림으로 전달 할 것이고 서버에서 메세지를 읽기 위해 입력스트림을 연결해야 하기 때문이다. 또한 서버에서 클라이언트로 메세지를 보내는 것도 같은 이치이다.
그렇다면 출력과 입력을 위한 스트림을 얻어와야 하는데 이를 위해 소켓이 필요하다.
데이터를 수신하기 위한 입력스트림을 얻는 방법은
InputStream in = socket.getInputStream();
데이터를 송신하기 위한 출력스트림 얻는 방법
OutputStream out = socket.getOutputStream();
---------------------------------------------------------------------------------
Server 측에서 할일
서버소켓준비, 클라이언트 소켓 대기, Sender와 Receiver 스레드로 입출력 처리
Client 측에서 할일
서버연결, Sender와 Receiver 스레드로 입출력 처리
코드는 길어서 공개는 생략
[Java] 네트워크 통신
TCP/IP 프로토콜
연결 지향적인 방식으로 인터넷에서 사용되는 통신규칙
아이피 = 네트워크에 연결되어 있는 PC의 주소값
포트 = 네트워크를 통해 데이터를 주고 받을 때 사용되는 가상의 출구(0~65535)
소켓 = 데이터의 통신 출입구
자바에서는 소켓과 소켓의 연결의 기반으로 통신이 이루어 진다.
서버소켓 만들기
ServerSocket serverSocket = new ServerSocket(9000);
포트 번호 9000번인 서버소켓 객체를 만든다.
Socket socket = serverSocket.accept();
클라이언트 소켓을 기다렸다가 클라이언트가 접속할 때 클라이언트 소켓을 얻음
클라이언트 소켓
Socket socket = new Socket("###.###.###.###", 9000);
아이피와 포트를 이용해 서버접속
연결완료 끝! 쉽다,,,
연결 지향적인 방식으로 인터넷에서 사용되는 통신규칙
아이피 = 네트워크에 연결되어 있는 PC의 주소값
포트 = 네트워크를 통해 데이터를 주고 받을 때 사용되는 가상의 출구(0~65535)
소켓 = 데이터의 통신 출입구
자바에서는 소켓과 소켓의 연결의 기반으로 통신이 이루어 진다.
서버소켓 만들기
ServerSocket serverSocket = new ServerSocket(9000);
포트 번호 9000번인 서버소켓 객체를 만든다.
Socket socket = serverSocket.accept();
클라이언트 소켓을 기다렸다가 클라이언트가 접속할 때 클라이언트 소켓을 얻음
클라이언트 소켓
Socket socket = new Socket("###.###.###.###", 9000);
아이피와 포트를 이용해 서버접속
연결완료 끝! 쉽다,,,
[Java] 동기화
동기화라는 것은 단순히 말해 하나의 스레드가 critical section을 실행하고 있을 때 다른 스레드의 접근을 막는 것이라 할 수 있다.
동기화 방법
1. 동기화 블록 지정
synchronized(sharedArea){
실행문(critical section)
}
이와 같이 critical section을 동기화 블록으로 처리해 주고 sharedArea라는 공유 객체를 설정해 둠으로써 이 블록 뿐만 아니라 다른 지역 블록에서 이 공유 객체가 되어 있는 부분을 다 접근하지 못하게 막아 두는 것이다.
2. 동기화 메소드
synchronized void increaseNum(int num){
실행문(critical section)
}
메소드 자체에 동기화를 걸어 두어 동시에 스레드가 이 메소드를 접근하는 것을 차단하는 것이다.
동기화와 관련된 메소드
obj.wait();
다른 스레드로부터 신호가 오기를 기다린다.(얼음)
obj.notify();
다른 스레드로 신호를 보낸다.(땡!)
여기서 obj는 두 스레드가 공유하는 객체여야 한다는 점과 반드시 동기화 블록이나 동기화 메소드 내에 두어야 한다는 점에 유념하자.
동기화 방법
1. 동기화 블록 지정
synchronized(sharedArea){
실행문(critical section)
}
이와 같이 critical section을 동기화 블록으로 처리해 주고 sharedArea라는 공유 객체를 설정해 둠으로써 이 블록 뿐만 아니라 다른 지역 블록에서 이 공유 객체가 되어 있는 부분을 다 접근하지 못하게 막아 두는 것이다.
2. 동기화 메소드
synchronized void increaseNum(int num){
실행문(critical section)
}
메소드 자체에 동기화를 걸어 두어 동시에 스레드가 이 메소드를 접근하는 것을 차단하는 것이다.
동기화와 관련된 메소드
obj.wait();
다른 스레드로부터 신호가 오기를 기다린다.(얼음)
obj.notify();
다른 스레드로 신호를 보낸다.(땡!)
여기서 obj는 두 스레드가 공유하는 객체여야 한다는 점과 반드시 동기화 블록이나 동기화 메소드 내에 두어야 한다는 점에 유념하자.
[Java] 스레드간 커뮤니케이션의 필요성
각각의 스레드가 독립적으로 실행 될 때, 즉 서로가 서로에게 어떤 영향을 주지 않는 상황일 때는 전혀 문제가 발생하지 않는다.
하지만 같은 영역의 데이터를 읽거나 쓰게 될 때 두 스레스가 동시에 접근하여 사용한다면 문제가 발생하게 된다. 이 부부을 critical section이라고도 한다.
예를 들어 두 개의 스레드가 실행되고 있고 이 스레드들을 하나의 변수에 공동으로 접근하여 그 수를 하나씩 증가 시킨다고 하자.
그런 상황에서는 당연히 서로의 스레드가 자신에게 주어진 횟수만큼 데이터를 증가시키고 스레드를 종료할 거라고 생각할 것이다. 그러나 결과는 그렇지 않다.
그 이유는 하나의 스레드가 데이터를 읽어와 그 데이터의 값을 하나 증가시키기전에 다른 스레드에서 데이터를 증가 시켜버렸다면 두 스레드가 함께 증가시켜야 할만큼의 값의 증가는 일어나지 못하게 되는 것이다.
그렇다면 어떻게 이러한 문제점을 해결할 수 있을까?
첫번째 방법 : boolean을 활용하여 하나의 스레드가 작동 중일때 false로 flag를 표시하여 다른 스레드의 접근을 막아두는 것이다. 그러나 근본적인 해결 방법은 아니다. 왜냐면 boolean을 너무 자주 참조하여 비효율적이기 때문이다.
두번째 방법 : 동기화(synchronization)이다! 이 동기화를 통해 스레드간의 원활한 커뮤니케이션이 되도록 제어할 수 있다.
하지만 같은 영역의 데이터를 읽거나 쓰게 될 때 두 스레스가 동시에 접근하여 사용한다면 문제가 발생하게 된다. 이 부부을 critical section이라고도 한다.
예를 들어 두 개의 스레드가 실행되고 있고 이 스레드들을 하나의 변수에 공동으로 접근하여 그 수를 하나씩 증가 시킨다고 하자.
그런 상황에서는 당연히 서로의 스레드가 자신에게 주어진 횟수만큼 데이터를 증가시키고 스레드를 종료할 거라고 생각할 것이다. 그러나 결과는 그렇지 않다.
그 이유는 하나의 스레드가 데이터를 읽어와 그 데이터의 값을 하나 증가시키기전에 다른 스레드에서 데이터를 증가 시켜버렸다면 두 스레드가 함께 증가시켜야 할만큼의 값의 증가는 일어나지 못하게 되는 것이다.
그렇다면 어떻게 이러한 문제점을 해결할 수 있을까?
첫번째 방법 : boolean을 활용하여 하나의 스레드가 작동 중일때 false로 flag를 표시하여 다른 스레드의 접근을 막아두는 것이다. 그러나 근본적인 해결 방법은 아니다. 왜냐면 boolean을 너무 자주 참조하여 비효율적이기 때문이다.
두번째 방법 : 동기화(synchronization)이다! 이 동기화를 통해 스레드간의 원활한 커뮤니케이션이 되도록 제어할 수 있다.
[Java] Thread
스레드란 프로그램의 실행 흐름을 의미한다.
스레드 작성 방법은
1. Thread를 상속받아 run메소드를 오버라이딩 하는 방법
2. Runnable을 구현하여 run메소드를 오버라이딩 하는 방법
이 있다. 이유는? 다중 상속이 안되니깐 상속 받을 수 있을 땐 Thread상속 받으면 되고 이미 상속하는 클래스가 존재하면 Runnable인터페이스를 구현해야되기 때문이다.
두 스레드가 실행될 때 어느것이 먼저 시작할까?
우리는 알지 못한다. 왜냐면 CPU를 경합하는 과정에서 예측할 수 없이 둘 중 하나가 CPU 자원을 받아서 실행하기 때문이다.
스레드를 사용하기 위해서
1. 정의한 클래스나 인터페이스의 객체를 생성
2. starts();메소드 호출
스레드의 라이프 사이클
스레드의 상태는 run메소드 진입 전, run메소드 진입, run메소드 완료로 구분된다. 이중 run메소드 진입 상태는 다시 두 가지로 구분된다.
Runnable과 NotRunnable 상태가 그것이다.
스레드의 상태가 Runnable이 되어 CPU가 해당 스레드를 선택하여 실행 가능
또는 NotRunnable이 되게 하여 CPU가 해당 스레드를 선택하지 못한다. 즉, 실행할 수 없다.
Sleep();메소드와 wait(); 메소드를 통해 스레드를 NotRunnable하게 만들어 다른 스레드에세 CPU권한을 넘기기도 하면서 어느정도의 제어가 가능하다.
Thread는 예외를 발생시키는 메소드이다. 따라서 항상 예외를 처리해야함을 유의하자.
스레드 작성 방법은
1. Thread를 상속받아 run메소드를 오버라이딩 하는 방법
2. Runnable을 구현하여 run메소드를 오버라이딩 하는 방법
이 있다. 이유는? 다중 상속이 안되니깐 상속 받을 수 있을 땐 Thread상속 받으면 되고 이미 상속하는 클래스가 존재하면 Runnable인터페이스를 구현해야되기 때문이다.
두 스레드가 실행될 때 어느것이 먼저 시작할까?
우리는 알지 못한다. 왜냐면 CPU를 경합하는 과정에서 예측할 수 없이 둘 중 하나가 CPU 자원을 받아서 실행하기 때문이다.
스레드를 사용하기 위해서
1. 정의한 클래스나 인터페이스의 객체를 생성
2. starts();메소드 호출
스레드의 라이프 사이클
스레드의 상태는 run메소드 진입 전, run메소드 진입, run메소드 완료로 구분된다. 이중 run메소드 진입 상태는 다시 두 가지로 구분된다.
Runnable과 NotRunnable 상태가 그것이다.
스레드의 상태가 Runnable이 되어 CPU가 해당 스레드를 선택하여 실행 가능
또는 NotRunnable이 되게 하여 CPU가 해당 스레드를 선택하지 못한다. 즉, 실행할 수 없다.
Sleep();메소드와 wait(); 메소드를 통해 스레드를 NotRunnable하게 만들어 다른 스레드에세 CPU권한을 넘기기도 하면서 어느정도의 제어가 가능하다.
Thread는 예외를 발생시키는 메소드이다. 따라서 항상 예외를 처리해야함을 유의하자.
2013년 1월 20일 일요일
[Java] File클래스
파일 자체를 관리하는 클래스
물리적인 파일 -> 객체화
왜 필요한가?
파일클래스에 다양한 메소드를 제공하고 있다. 실제 파일의 정보를 확인하려면 상당히 까다로우나 파일클래스에서 제공하는 다양한 메소드를 이용하여 쉽게 알아볼 수 있다.
또한 디렉토리 관리에 좋다. 파일클래스는 파일 뿐만 아니라 폴더에 관한 관리도 가능하다.
File file = new File(".");
현재 패키지(폴더)를 기준으로한 파일 클래스 생성
파일 클래스에서 제공하는 다양한 메소드
exits(); 존재유무(boolean)
isFile(); 파일유무(boolean)
isDrectory(); 디렉토리유무(boolean);
getName();파일이름
lastModified();최근수정정보
canRead();
canWrite();
isHidden();
getParent();
listFiles();파일에 속하는 모든 파일과 하위 폴더 및 파일정보 배열
createNewFile();
delete();
실제 파일 생성과 삭제
mkdir();
delete();
디렉토리 생성과 삭제
물리적인 파일 -> 객체화
왜 필요한가?
파일클래스에 다양한 메소드를 제공하고 있다. 실제 파일의 정보를 확인하려면 상당히 까다로우나 파일클래스에서 제공하는 다양한 메소드를 이용하여 쉽게 알아볼 수 있다.
또한 디렉토리 관리에 좋다. 파일클래스는 파일 뿐만 아니라 폴더에 관한 관리도 가능하다.
File file = new File(".");
현재 패키지(폴더)를 기준으로한 파일 클래스 생성
파일 클래스에서 제공하는 다양한 메소드
exits(); 존재유무(boolean)
isFile(); 파일유무(boolean)
isDrectory(); 디렉토리유무(boolean);
getName();파일이름
lastModified();최근수정정보
canRead();
canWrite();
isHidden();
getParent();
listFiles();파일에 속하는 모든 파일과 하위 폴더 및 파일정보 배열
createNewFile();
delete();
실제 파일 생성과 삭제
mkdir();
delete();
디렉토리 생성과 삭제
[Java] 문자스트림
자바는 유니코드를 기반으로 문자를 인코딩하고 디코딩한다. 그러나 자바끼리 문자를 읽고 쓰는데 있어서 굳이 문자 스트림으로 연결할 필요는 없다. 바이트 스트림으로도 충분히 인코딩과 디코딩이 잘 이뤄질 수 있기 때문이다.
그렇다면 자바를 돌리는 OS에 따른 문자 인코딩, 디코딩 방식과는 어떤 관계가 있을까?
자바에서 바이트 스트림을 통해 저장된 데이터 자체는 전혀 OS환경에 영향을 받지 않는다. 그러나 문자라면 이야기가 달라진다. 예를 들어 window기반에서 자바에서 작성한 텍스트파일을 읽으려고 한다면 꼭 문자 스트림을 활용해 데이터를 저장해 둬야 할 것이다.
따라서 문자를 입력하고 출력한다고 해서 꼭 문자 스트림을 연결해야한다는 생각을 하지말고 어떤 경우에 바이트 스트림을 사용할지 또 어떤 경우에 문자 스트림을 사용할지 경우에 따라 잘 선택적으로 사용하는 것이 바람직할 것이다.
이러한 이유로 사실은 바이트 스트림이 문자 스트림보다 훨씬 많이 사용되어 진다는 점에 유념하자.
그렇다면 자바를 돌리는 OS에 따른 문자 인코딩, 디코딩 방식과는 어떤 관계가 있을까?
자바에서 바이트 스트림을 통해 저장된 데이터 자체는 전혀 OS환경에 영향을 받지 않는다. 그러나 문자라면 이야기가 달라진다. 예를 들어 window기반에서 자바에서 작성한 텍스트파일을 읽으려고 한다면 꼭 문자 스트림을 활용해 데이터를 저장해 둬야 할 것이다.
따라서 문자를 입력하고 출력한다고 해서 꼭 문자 스트림을 연결해야한다는 생각을 하지말고 어떤 경우에 바이트 스트림을 사용할지 또 어떤 경우에 문자 스트림을 사용할지 경우에 따라 잘 선택적으로 사용하는 것이 바람직할 것이다.
이러한 이유로 사실은 바이트 스트림이 문자 스트림보다 훨씬 많이 사용되어 진다는 점에 유념하자.
[Java] 입출력
자바는 입력과 출력에 있어서 해당하는 장치나 모니터, 파일에 관계없이 일정한 인터페이스의 구현만으로 입출력이 가능하도록 되어있다.
이것이 자바가 가지는 큰 장점이다.
그러나 입출력에 관련된 다양한 클래스를 그져 외우고 많이 아는 것보다 관련 클래스들의 조합이 더 중요하다.
기본 입출력 스트림인 2개의 인터페이스를 다양한 필터스트림과의 연결을 통해 다양한 입출력이 가능해 지는 것이다.
파일을 예로들면 파일에서 스트림을 통해 바이트를 읽어올때 당연히 FileInputStream이 필요하게 되는데 InputStream을 상속한 클래스라는 것을 이름을 통해 알 수 있다.
이 FileInputStream을 통해 데이터를 읽는 것이 가능하다. 그러나 성능을 향상시킬 수 있는 더 많은 클래스들이 존재하고 이런 클래스들을 필터클래스라고 한다.
즉, FileInputStream에 BufferedInputStream을 연결 시키면 한번에 많은 데이터를 파일로 부터 읽어들여 버퍼에 저장하여 읽어 낼 수 있기 때문에 성능의 향상이 보장된다.
이러한 필터의 조합을 어떻게 연결할 것인가를 고민하고 사용하는 자세가 필요하고 이를 잘 이해한다면 네트워크 관련해서 일어나는 스트림 연결을 이해하는데 도움이 될 것이다.
이것이 자바가 가지는 큰 장점이다.
그러나 입출력에 관련된 다양한 클래스를 그져 외우고 많이 아는 것보다 관련 클래스들의 조합이 더 중요하다.
기본 입출력 스트림인 2개의 인터페이스를 다양한 필터스트림과의 연결을 통해 다양한 입출력이 가능해 지는 것이다.
파일을 예로들면 파일에서 스트림을 통해 바이트를 읽어올때 당연히 FileInputStream이 필요하게 되는데 InputStream을 상속한 클래스라는 것을 이름을 통해 알 수 있다.
이 FileInputStream을 통해 데이터를 읽는 것이 가능하다. 그러나 성능을 향상시킬 수 있는 더 많은 클래스들이 존재하고 이런 클래스들을 필터클래스라고 한다.
즉, FileInputStream에 BufferedInputStream을 연결 시키면 한번에 많은 데이터를 파일로 부터 읽어들여 버퍼에 저장하여 읽어 낼 수 있기 때문에 성능의 향상이 보장된다.
이러한 필터의 조합을 어떻게 연결할 것인가를 고민하고 사용하는 자세가 필요하고 이를 잘 이해한다면 네트워크 관련해서 일어나는 스트림 연결을 이해하는데 도움이 될 것이다.
2013년 1월 17일 목요일
[Java] 입출력 기능/성능 향상 클래스와 직렬화
입출력을 향상시키는 클래스들이 존재한다.
DataInputStream / DataOutputStrea
ObjectOutputStream / ObjectInputStream
BufferedReader / BufferedWriter
등이다. 이런 클래스들을 필터클래스라고도 한다.(노드클래스는 최상위 클래스라 언급했다)
특히 Object를 읽고 쓰기 위한 ObjectOutputStream과 ObjectInputStream을 잘 알아두자.
객체의 직렬화를 위해 꼭 알아야한다.
직렬화란 객체를 스트림을 이용하여 바이트로 쓰고
역직렬화란 바이트를 스트림으로부터 읽어들어 객체로 만드는 것이다.
객체를 그냥 막 쓰고 읽어 낼 수 있다는 말이다! 하지만 모든 객체가 직렬화가 될까?
그렇지는 않다.
그럼 어떤 객체가 직렬화 될 수 있을까???
바로 Serializable 인터페이스를 구현한 객체만이 직렬화가 가능하다.
Serializable 인터페이스는 그냥 빈 인터페이스다. 하지만 직렬화가 가능한 객체와 아닌 객체를 구분하기 위해서는 꼭 implements 해줘야 한다! 잊지말자!
그럼 직렬화를 하면 객체의 모든 것을 스트림으로 전달할 수 있을까?
아니다. 단지 멤버변수만 전달이 가능하다. 그리고 멤버변수중 transient키워드로 직렬화 대상에서 제외시킬 수 있다.
객체에 있는 많은 멤버변수들의 정보를 객체로 넘겨주면 얼마나 많은 이점을 있을까? 그것은 한번 생각해보자.
DataInputStream / DataOutputStrea
ObjectOutputStream / ObjectInputStream
BufferedReader / BufferedWriter
등이다. 이런 클래스들을 필터클래스라고도 한다.(노드클래스는 최상위 클래스라 언급했다)
특히 Object를 읽고 쓰기 위한 ObjectOutputStream과 ObjectInputStream을 잘 알아두자.
객체의 직렬화를 위해 꼭 알아야한다.
직렬화란 객체를 스트림을 이용하여 바이트로 쓰고
역직렬화란 바이트를 스트림으로부터 읽어들어 객체로 만드는 것이다.
객체를 그냥 막 쓰고 읽어 낼 수 있다는 말이다! 하지만 모든 객체가 직렬화가 될까?
그렇지는 않다.
그럼 어떤 객체가 직렬화 될 수 있을까???
바로 Serializable 인터페이스를 구현한 객체만이 직렬화가 가능하다.
Serializable 인터페이스는 그냥 빈 인터페이스다. 하지만 직렬화가 가능한 객체와 아닌 객체를 구분하기 위해서는 꼭 implements 해줘야 한다! 잊지말자!
그럼 직렬화를 하면 객체의 모든 것을 스트림으로 전달할 수 있을까?
아니다. 단지 멤버변수만 전달이 가능하다. 그리고 멤버변수중 transient키워드로 직렬화 대상에서 제외시킬 수 있다.
객체에 있는 많은 멤버변수들의 정보를 객체로 넘겨주면 얼마나 많은 이점을 있을까? 그것은 한번 생각해보자.
[Java] BufferedReader 활용하기
public class BufferExam {
public static void main(String[] args) throws Exception {
/*InputStream in = System.in;
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);*/
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//잘 알아둘것!
String str = null;
BufferedWriter bw = new BufferedWriter(new FileWriter("kyd.txt"));
try{
while((str = br.readLine())!=null){
bw.write(str + "\n");
}
}catch(Exception e){
e.printStackTrace();
}
finally{
try{
br.close();
bw.close();
}catch(Exception e2){
}
}
}
}
위에 붉게 표시한 부분 둘다 같은 의미이다.
처음 노드스트림에 InputStreamReader라는 필터 스트림에 연결하고 BufferedReader라는 향상된 필터스트림과 연결하고 있다.
[Java] 파일 읽기와 쓰기
자바에서는 앞서 말했던 것과 같이 파일의 입출력이 그렇게 어렵지 않다. 하나씩 살펴보자.
FileReader 클래스
1. FileReader reader = new FileReader("Source.txt");
문자를 읽어들일 문자스트림과 파일 연결
2. int data = reader.read();
문자 하나씩 읽기.
중요한 것은 더이상 읽어들일 문자가 없을 때 -1을 리턴
while(true){
int data = reader.read();
if(data == -1)
break;
char ch = (char)data;
데이터처리부분
}
3. reader.close();
파일 닫기. 꼭!
자바 입출력에서는 반드시 익셉션을 처리해야 한다.
특히 파일을 읽고 쓸때 항상 예외가 존재한다.(예 파일이 존재하지 않을 경우)
때문에 항상 파일을 다룰때는 예외를 반드시 확인하고 처리해 주는 버릇을 기르자.
FileWriter 클래스
1. FileWriter writer = new FileWriter("Save.txt");
문자를 쓸 문자스트림과 파일을 연결
2. writer.write(ch);
문자 하나를 파일에 쓰기
3. writer.close();
파일 닫기
파일쓰는 방법도 파일 읽는 방법과 비슷하다.
FileReader 클래스
1. FileReader reader = new FileReader("Source.txt");
문자를 읽어들일 문자스트림과 파일 연결
2. int data = reader.read();
문자 하나씩 읽기.
중요한 것은 더이상 읽어들일 문자가 없을 때 -1을 리턴
while(true){
int data = reader.read();
if(data == -1)
break;
char ch = (char)data;
데이터처리부분
}
3. reader.close();
파일 닫기. 꼭!
자바 입출력에서는 반드시 익셉션을 처리해야 한다.
특히 파일을 읽고 쓸때 항상 예외가 존재한다.(예 파일이 존재하지 않을 경우)
때문에 항상 파일을 다룰때는 예외를 반드시 확인하고 처리해 주는 버릇을 기르자.
FileWriter 클래스
1. FileWriter writer = new FileWriter("Save.txt");
문자를 쓸 문자스트림과 파일을 연결
2. writer.write(ch);
문자 하나를 파일에 쓰기
3. writer.close();
파일 닫기
파일쓰는 방법도 파일 읽는 방법과 비슷하다.
[Java] 파일 입출력
스트림이란? 데이터의 흐름이다.
왜 필요하나? 어떤 목적지(파일 등)에서 데이터를 읽어오기 위한 통로(배관)과 같은 것이 필요하기 때문이다. 따라서 스트림은 데이터가 흐를 수 있도록, 즉 전달 할 수 있도록 해주는 통로 역할을 해준다.
System클래스 안에는 이 스트림을 가질 수 있도록 정의되어 있는데 in과 out이라는 멤버객체가 그것이다.
그러나 스트림의 종류는 다양하다. 왜 그럴까?
그만큼 스트림을 지나는 데이터의 내용이 다양하기 때문이다.
대표적으로 바이트와 문자 스트림에 대해 알아보자.
바이트 스트림
바이트 스트림의 최상위 클래스는 InputStream / OutputStream 이다.(노드 스트림이라고도 한다.) 가장 기본적인 스트림이라고 할 수 있는데 당연히 바이트의 흐름만 통과할 수 있다. 이 클래스를 상속하는 클래스가 다양하다. (예: FileInputStream / FileOutputStream ,,,)
문자 스트림
문자 스트림의 최상위 클래스는 Reader / Writer 이다. 문자의 흐름을 읽거나 쓸 수 있다. 이 클래스를 상속하는 클래스가 다양하다. (예: FileReader / FileWriter ,,, )
이 스트림이 최상위 클래스이기 때문에 이를 상속하는 모든 클래스들의 이름을 잘 보면 비슷하게 구성되어 있다는 것을 잘 알 수 있다. 그 연관성이 있으니까 외우기가 어렵지는 않을 것이다.
그렇다면 파일 입출력의 과정은 어떻게 될까?
파일을 열고, 읽고, 닫거나
파일을 열고, 쓰고, 닫으면 끝
왜 필요하나? 어떤 목적지(파일 등)에서 데이터를 읽어오기 위한 통로(배관)과 같은 것이 필요하기 때문이다. 따라서 스트림은 데이터가 흐를 수 있도록, 즉 전달 할 수 있도록 해주는 통로 역할을 해준다.
System클래스 안에는 이 스트림을 가질 수 있도록 정의되어 있는데 in과 out이라는 멤버객체가 그것이다.
그러나 스트림의 종류는 다양하다. 왜 그럴까?
그만큼 스트림을 지나는 데이터의 내용이 다양하기 때문이다.
대표적으로 바이트와 문자 스트림에 대해 알아보자.
바이트 스트림
바이트 스트림의 최상위 클래스는 InputStream / OutputStream 이다.(노드 스트림이라고도 한다.) 가장 기본적인 스트림이라고 할 수 있는데 당연히 바이트의 흐름만 통과할 수 있다. 이 클래스를 상속하는 클래스가 다양하다. (예: FileInputStream / FileOutputStream ,,,)
문자 스트림
문자 스트림의 최상위 클래스는 Reader / Writer 이다. 문자의 흐름을 읽거나 쓸 수 있다. 이 클래스를 상속하는 클래스가 다양하다. (예: FileReader / FileWriter ,,, )
이 스트림이 최상위 클래스이기 때문에 이를 상속하는 모든 클래스들의 이름을 잘 보면 비슷하게 구성되어 있다는 것을 잘 알 수 있다. 그 연관성이 있으니까 외우기가 어렵지는 않을 것이다.
그렇다면 파일 입출력의 과정은 어떻게 될까?
파일을 열고, 읽고, 닫거나
파일을 열고, 쓰고, 닫으면 끝
[Java] HashMap 예제
void addGroup(String group){
if(!map.containsKey(group)){
map.put(group, new ArrayList<PhoneInfo>());
}
}
void Input(){
System.out.print("그룹 입력 : ");
String group = sc.nextLine();
System.out.print("이름 입력 : ");
String name = sc.nextLine();
System.out.print("전화 번호 입력 : ");
String phone = sc.nextLine();
System.out.print("생일 입력 : ");
String birth = sc.nextLine();
addGroup(group);
ArrayList<PhoneInfo> list = map.get(group);
list.add(new PhoneInfo(name, phone, birth));
System.out.println();
}
void show(){
Set set = map.entrySet();
Iterator iter = set.iterator();
while(iter.hasNext()){
Map.Entry e = (Map.Entry)iter.next();
Iterator iterSub = ((ArrayList)e.getValue()).iterator();
System.out.println(e.getKey());
while(iterSub.hasNext()){
PhoneInfo pi = (PhoneInfo)(iterSub.next());
pi.showInfo();
}
System.out.println();
}
System.out.println();
}
void modify(){
System.out.print("전화번호부 수정할 사람의 이름을 입력해 주십시오");
String name = sc.nextLine();
Set set = map.entrySet();
Iterator iter = set.iterator();
while(iter.hasNext()){
Map.Entry e = (Map.Entry)iter.next();
Iterator iterSub = ((ArrayList)e.getValue()).iterator();
while(iterSub.hasNext()){
PhoneInfo pi = (PhoneInfo)(iterSub.next());
if(pi.name.equals(name)){
System.out.print("수정할 전화번호를 입력하세요");
String phone = sc.nextLine();
pi.phoneNum = phone;
}
}
}
System.out.println();
}
void delete(){
System.out.print("삭제할 사람의 이름을 입력해 주십시오.");
String name = sc.nextLine();
Set set = map.entrySet();
Iterator iter = set.iterator();
while(iter.hasNext()){
Map.Entry e = (Map.Entry)iter.next();
Iterator iterSub = ((ArrayList)e.getValue()).iterator();
while(iterSub.hasNext()){
PhoneInfo pi = (PhoneInfo)(iterSub.next());
if(pi.name.equals(name)){
iterSub.remove();
}
}
}
}
void sort(){
Comparator<PhoneInfo> cp = new Comparator<PhoneInfo>() {
@Override
public int compare(PhoneInfo o1, PhoneInfo o2) {
// TODO Auto-generated method stub
if(o1.name.compareTo(o2.name)<0)
return -1;
else if(o1.name.compareTo(o2.name)>0)
return 1;
return 0;
}
};
Set set = map.entrySet();
Iterator iter = set.iterator();
System.out.print("정렬할 그룹를 입력하세요");
String group = sc.nextLine();
while(iter.hasNext()){
Map.Entry e = (Map.Entry)iter.next();
if(e.getKey().equals(group))
Collections.sort(((ArrayList)e.getValue()), cp);
}
System.out.println();
}
---------------------------------------------------------------------------------
HashMap 안에 HashMap 또는 ArrayList를 사용할 수 있다. 옆에 간략하게 나타낸 이미지를 통해 어떤 메소드를 호출하고 형변환이 일어나는지 잘 파악해보자.
2013년 1월 16일 수요일
[Java] HashMap을 활용한 또다른 예제
public class MapExam02 {
public static void main(String[] args) {
// 성적관리 프로그램
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("김용도", 100);
map.put("현학준", 90);
map.put("신동민", 80);
map.put("윤상수", 80);
map.put("홍길동", 70);
Set set = map.keySet();
System.out.println("시험명단: " + set);
//Map => Collection => Iterator
Collection values = map.values();//value값들 넣기
Iterator iter = values.iterator();
int total = 0;
while(iter.hasNext()){
total += (Integer)iter.next();
}
System.out.println("총점 : " + total);
System.out.println("평균 : " + (double)total/map.size());
System.out.println("최대값 : " + Collections.max(values));
System.out.println("최소값 : " + Collections.min(values));
}
}
---------------------------------------------------------------------------------
이 예제를 보면 앞서 했던 예제와 비슷한 과정이 진행된다.
즉 map을 Iterator로 받고 싶지만 그럴 수 없기 때문에 map.values()메소드를 호출한다. 이 메소드는 Value들을 Collection 인터페이스가 받을 수 있는 형태로 리턴해 준다. 그러므로 Collection 인터페이스가 필요하다!
Collection 인터페이스에 iterator()메소드를 호출하면 바로 Iterator화 할 수 있고 메소드를 활용할 수 있다.
사실 Collection 은 Iterable을 구현하였고 Set은 Collection을 구현하고 있는 관계이다.
[Java] HashMap
Key와 Value로 구성된 맵구조를 구현한 클래스이다.
HashMap<String, Integer> map = new HashMap<String, Integer>();
몇가지 메소드를 살펴보면
map.put("Kevin", 40); Key와 Value 입력
map.get("Kevin"); Key로 Value 얻기
map.remove("Kevin"); Key로 해당 Key와 Value 삭제
map.containsKey("Kevin"); Key값으로 존재 유무 확인
Set set = map.entrySet();
해쉬에서는 바로 Iterator인터페이스를 활용할 수 없다. 그러나 entrySet();이란 메소드를 통해 Iterable 인터페이스를 구현한 Set 객체를 활용할 수 있다. 이 Set클래스의 메소드에서 iterator()메소드를 호출하면 드디어 Iterator 인터페이스를 활용할 수 있는 것이다. (즉 이 Iterator의 위치가 되고 싶어서 Set이란 인터페이스를 거치는 과정이다.)
따라서 iter.hasNext()를 호출할수 있다.
그러나 문제는 바로 iter.next()를 사용할 수 없다. 방법은 Map.Entry를 사용하는 것이다.
Map.Entry e = (Map.Entry)iter.next();
Map.Entry를 API에서 찾아보면 Map인터페이스 안에 구현되어 있는 내부 정적 인터페이스이다. 즉 개체생성을 하지 않더라도 인터페이스 이름으로 접근하여 메소드를 사용할 수 있으리라. Map이라는 인터페이스만 보더라도 Hashmap이 Map인터페이스를 구현하고 있다는 것은 당연하다.
iter.next()메소드는 제네릭을 반환하는데 이 제네릭을 Map.Entry로 형변환하면 Key와 Value를 다룰 수 있는 것이다. 그리하여 e를 이용하여 getKey()와 getValue()를 사용하면 원래 map에 있는 Key와 Value를 활용할 수 있다.
HashMap<String, Integer> map = new HashMap<String, Integer>();
몇가지 메소드를 살펴보면
map.put("Kevin", 40); Key와 Value 입력
map.get("Kevin"); Key로 Value 얻기
map.remove("Kevin"); Key로 해당 Key와 Value 삭제
map.containsKey("Kevin"); Key값으로 존재 유무 확인
Set set = map.entrySet();
Iterator iter = set.iterator();
while(iter.hasNext()){
Map.Entry e = (Map.Entry)iter.next();//정적내부 인터페이스 Entry
System.out.println("key: " + e.getKey() + ", value: " + e.getValue());
System.out.println(e);
}
따라서 iter.hasNext()를 호출할수 있다.
그러나 문제는 바로 iter.next()를 사용할 수 없다. 방법은 Map.Entry를 사용하는 것이다.
Map.Entry e = (Map.Entry)iter.next();
Map.Entry를 API에서 찾아보면 Map인터페이스 안에 구현되어 있는 내부 정적 인터페이스이다. 즉 개체생성을 하지 않더라도 인터페이스 이름으로 접근하여 메소드를 사용할 수 있으리라. Map이라는 인터페이스만 보더라도 Hashmap이 Map인터페이스를 구현하고 있다는 것은 당연하다.
iter.next()메소드는 제네릭을 반환하는데 이 제네릭을 Map.Entry로 형변환하면 Key와 Value를 다룰 수 있는 것이다. 그리하여 e를 이용하여 getKey()와 getValue()를 사용하면 원래 map에 있는 Key와 Value를 활용할 수 있다.
피드 구독하기:
글 (Atom)

