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라는 메소드를 오버라이딩하면 버튼으로부터 생겨난 이벤트를 이 메소드가 처리해 주게 된다.

[Java] GUI기반 프로그래밍

자바에서는 GUI기반 프로그래밍 기법도 제공한다. 그러나 그리 흔히 쓰이지는 않는다고 한다. 그렇지만 그래픽기반 프로그래밍을 통해 느낄 수 있는 것들이 실제로 많이 있다. 예를 들어 어떻게 레이아웃을 구성하고 어떻게 이벤트를 처리해줘야 할지 등등이다. 이러한 것들을 알고 있어야 윈도우나 다른 OS기반의 GUI프로그래밍을 하는데 어려움이 없을 것이다.

자바에는 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 스레드로 입출력 처리

코드는 길어서 공개는 생략

[Java] 네트워크 통신

TCP/IP 프로토콜
연결 지향적인 방식으로 인터넷에서 사용되는 통신규칙

아이피 = 네트워크에 연결되어 있는 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는 두 스레드가 공유하는 객체여야 한다는 점과 반드시 동기화 블록이나 동기화 메소드 내에 두어야 한다는 점에 유념하자.

[Java] 스레드간 커뮤니케이션의 필요성

각각의 스레드가 독립적으로 실행 될 때, 즉 서로가 서로에게 어떤 영향을 주지 않는 상황일 때는 전혀 문제가 발생하지 않는다.

하지만 같은 영역의 데이터를 읽거나 쓰게 될 때 두 스레스가 동시에 접근하여 사용한다면 문제가 발생하게 된다. 이 부부을 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는 예외를 발생시키는 메소드이다. 따라서 항상 예외를 처리해야함을 유의하자.


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();
디렉토리 생성과 삭제

[Java] 문자스트림

자바는 유니코드를 기반으로 문자를 인코딩하고 디코딩한다. 그러나 자바끼리 문자를 읽고 쓰는데 있어서 굳이 문자 스트림으로 연결할 필요는 없다. 바이트 스트림으로도 충분히 인코딩과 디코딩이 잘 이뤄질 수 있기 때문이다.

그렇다면 자바를 돌리는 OS에 따른 문자 인코딩, 디코딩 방식과는 어떤 관계가 있을까?

자바에서 바이트 스트림을 통해 저장된 데이터 자체는 전혀 OS환경에 영향을 받지 않는다. 그러나 문자라면 이야기가 달라진다. 예를 들어 window기반에서 자바에서 작성한 텍스트파일을 읽으려고 한다면 꼭 문자 스트림을 활용해 데이터를 저장해 둬야 할 것이다.

따라서 문자를 입력하고 출력한다고 해서 꼭 문자 스트림을 연결해야한다는 생각을 하지말고 어떤 경우에 바이트 스트림을 사용할지 또 어떤 경우에 문자 스트림을 사용할지 경우에 따라 잘 선택적으로 사용하는 것이 바람직할 것이다.

 이러한 이유로 사실은 바이트 스트림이 문자 스트림보다 훨씬 많이 사용되어 진다는 점에 유념하자.

[Java] 입출력

자바는 입력과 출력에 있어서 해당하는 장치나 모니터, 파일에 관계없이 일정한 인터페이스의 구현만으로 입출력이 가능하도록 되어있다.

이것이 자바가 가지는 큰 장점이다.

그러나 입출력에 관련된 다양한 클래스를 그져 외우고 많이 아는 것보다 관련 클래스들의 조합이 더 중요하다.

기본 입출력 스트림인 2개의 인터페이스를 다양한 필터스트림과의 연결을 통해 다양한 입출력이 가능해 지는 것이다.

파일을 예로들면 파일에서 스트림을 통해 바이트를 읽어올때 당연히 FileInputStream이 필요하게 되는데 InputStream을 상속한 클래스라는 것을 이름을 통해 알 수 있다.
 이 FileInputStream을 통해 데이터를 읽는 것이 가능하다. 그러나 성능을 향상시킬 수 있는 더 많은 클래스들이 존재하고 이런 클래스들을 필터클래스라고 한다.

 즉, FileInputStream에 BufferedInputStream을 연결 시키면 한번에 많은 데이터를 파일로 부터 읽어들여 버퍼에 저장하여 읽어 낼 수 있기 때문에 성능의 향상이 보장된다.

이러한 필터의 조합을 어떻게 연결할 것인가를 고민하고 사용하는 자세가 필요하고 이를 잘 이해한다면 네트워크 관련해서 일어나는 스트림 연결을 이해하는데 도움이 될 것이다.

2013년 1월 17일 목요일

[Java] 입출력 기능/성능 향상 클래스와 직렬화

입출력을 향상시키는 클래스들이 존재한다.

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();
파일 닫기

파일쓰는 방법도 파일 읽는 방법과 비슷하다.

[Java] 파일 입출력

스트림이란? 데이터의 흐름이다.
왜 필요하나? 어떤 목적지(파일 등)에서 데이터를 읽어오기 위한 통로(배관)과 같은 것이 필요하기 때문이다. 따라서 스트림은 데이터가 흐를 수 있도록, 즉 전달 할 수 있도록 해주는 통로 역할을 해준다.

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

해쉬에서는 바로 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를 활용할 수 있다.

[Java] Collections 클래스

데이터를 담아서 조작하는데 많이 사용되는 클래스인듯

API를 보면 모든 메소드와 변수가 static으로 선언되어 있다. 따라서 이 클래스를 객체로 생성하여 사용하는 클래스가 아니라 오로지 다양한 함수와 변수를 호출하는 공용클래스로써 사용된다.

예를들어

Collections.sort( , );

이렇게 클래스 이름으로 메소드를 호출!

특히 자료구조와 함께 많이 사용된다.
자료구조는 다양하기 때문에 각각의 자료구조에 맞는 꼭 필요한 메소드들이 존재하므로 자료구조를 이용하다가 Collections 클래스를 틈틈히 살펴보도록 하자.

[Java] 비교를 통한 정렬!


public void sort() {

Comparator<Board> cp = new Comparator<Board>() {

@Override
public int compare(Board o1, Board o2) {
// TODO Auto-generated method stub
if(o1.getName().compareTo(o2.getName())<0)
return -1;
elseif (o1.getName().compareTo(o2.getName())>0)
return 1;
else
return 0;
}
};// 익명 내부 인터페이스(클래스)

Collections.sort(list, cp);
}

---------------------------------------------------------------------------------

익명 내부 인터페이스를 정의하여 사용해보았다!
Comparator는 인터페이스로서 객체로 생성할 수 없으며 항상 메소드를 오버라이딩하여야 한다. 익명 내부 인터페이스를 정의하여 사용하면 객체를 임시적으로 생성하여 메소드를 사용할 수가 있어서 번거로운 인터페이스 구현이나 클래스 상속후 오버라이딩 해줘야하는 일이 줄어든다.

아무튼 cp라는 Comparator인터페이스의 compare메소드를 오버라이딩한뒤 static 메소드 Collections.sort(); 메소드를 호출하여 정렬하고 있다.

2013년 1월 15일 화요일

[Java] 자료구조

자료구조란 데이터를 효율적으로 사용할 수 있도록 구조를 만들어서 저장해 놓고 관리하는 것이다.

자바에는 다양한 자료구조를 클래스로 제공하고 있어서 new키워드로 쉽게 구현할 수 있다.
더나아가 클래스에 정의되어 있는 유용한 메소드는 강력하다.

따라서 개발자는 자료구조를 어떻게 구현하는지보단 어떻게 활용할 것인지에 대한 측면에서 접근하여 개발에 집중할 수 있다.

자료구조 중 가장 많이 사용되는 자료구조는 ArrayList이다.

ArrayList<E> list = new ArrayList<E>();

요롷게 객체를 생성하여 사용하면 그만이다. 쉽다. 여기서 <E>는 제네릭을 뜻하는데 제네릭은 어떤 객체의 참조변수를 담을지 결정하도록 미리 객체를 생성하면서 제한을 두는 것이다. 이렇게 하면 서로 다른 참조변수를 담을 위험성이 사라진다.

사용법은 간단하다.
1. 자료구조 생성
2. 데이터 삽입
3. 데이터 출력

이와같은 순서로 많이 사용될 것이다.


[Java] Wrapper 클래스

프로그래밍에서 데이터의 자료형은 엄격하기 마련이다. 
따라서 항상 데이터형을 잘 매치시켜주는 것이 중요하다.

add(Object obj);
오브젝트형 obj를 인자로 받아야하는 add메소드에 100이라는 정수가 전달 되어 호출될 수 있을까???

원래는 절대 불가능하다. 어떻게 int형 정수가 참조변수인 Object형이 되겠는가.

하지만! 자바에서는 가능하다. 그 이유가 바로 wrapper클래스 덕분이다.

Integer obj = new Integer(1324);

Integer라는 클래스를 생성하면서 정수 1324를 전달하고 있다. 이것이 의미하는 바는 정수가 객체화 되는 것을 볼 수 있는 것이다. 이제 obj는 완벽한 하나의 객체이다. 따라서 Object형 객체로서 마음껏 활용가능하다는 것이다.

int num = obj.intValue();

다음은 obj 객체를 다시 정수로 변환하는 것을 보여준다.

그러나 이렇게 명시적으로 형을 변환시켜 주지 않더라도 자동으로 형이 변하는 경우가 상당히 많다. 그것을 Boxing과 Unboxing이라고 한다.

따라서 위에 

add(100);
이란 메소드를 호출하면 정수 100이 Integer클래스로 Boxing이 자동적으로 되고 

int sum = obj + 20;
을 하게 되면 obj는 자동적으로 Unboxing이 되어 정수가 된다.

좋지 아니한가???

[Java] Calendar 클래스와 GregorianCalendar



public class Calender_Exam {


public static void main(String[] args) {

GregorianCalendar gc = new GregorianCalendar();//객체생성

System.out.println(gc);

String now = gc.get(Calendar.YEAR) + "년 "
                                + (gc.get(Calendar.MONTH)+1) + "월 "
+ gc.get(Calendar.DATE) + "일 "
                                + gc.get(Calendar.HOUR) + "시 "
+ gc.get(Calendar.MINUTE) + "분 ";

System.out.println(now);

gc.add(Calendar.DATE, 1000);
String future = gc.get(Calendar.YEAR) + "년 "
                                + (gc.get(Calendar.MONTH)+1) + "월 "
+ gc.get(Calendar.DATE) + "일 "
                                + gc.get(Calendar.HOUR) + "시 "
+ gc.get(Calendar.MINUTE) + "분 ";

System.out.println("1000일 후 : " + future);

gc.set(2010, 4, 20);

SimpleDateFormat date = new SimpleDateFormat("yyyy년 MM월 dd일 hh시 mm분");//날짜 포맷 지정

String str = date.format(gc.getTime());
System.out.println(str);

char[] week  = {'일', '월', '화', '수', '목', '금', '토'};

for(int i=2013; i<=2020; i++){
gc.set(i, 11, 25);
char s = week[gc.get(Calendar.DAY_OF_WEEK)-1];
System.out.println(i + "년의 크리스마스는 " + s + "요일입니다.");
}
}

}

---------------------------------------------------------------------------------


public class Calender_Mission {

public static void main(String[] args) {

GregorianCalendar gc = new GregorianCalendar();
Scanner sc = new Scanner(System.in);

while(true){
System.out.println("달력 출력프로그램입니다.");
System.out.println("년과 월을 입력하세요");
String str = sc.nextLine();
StringTokenizer st = new StringTokenizer(str);
int year = Integer.parseInt(st.nextToken());
int month = Integer.parseInt(st.nextToken());

gc.set(year, month-1, 1);//지정한 날로 가리키기
int sWeek = gc.get(Calendar.DAY_OF_WEEK);
System.out.println("<" + year + "년 " + month + "월>");
System.out.println("일\t월\t화\t수\t목\t금\t토");
for(int i=1; i<sWeek; i++){
System.out.print("\t");
}

for(int i=1; i<=gc.getActualMaximum(Calendar.DATE); i++){
if((sWeek+i-2)%7==0){
System.out.println();
}
System.out.print(i + "\t");
}
System.out.println();
System.out.println();
}
}

}

2013년 1월 14일 월요일

[Java] 난수 발생!

자바에서 난수를 발생하는 메소드가 Math클래스에서 static으로 정의되어 있다. 즉, 클래스 이름으로 어디서든 접근하여 사용할 수 있다.
형태는 다음과 같다.

Math.random();

0.0부터 1.0미만인 실수값을 돌려주는데 랜덤하게 돌려주기 때문에 그 값을 예측할 수 없다.
그러나 실수 자체로 사용되는 일은 드물기 때문에 다음과 같이 정수형으로 많이 사용한다.

int num = (int)(Math.random());

이렇게 하면 0만 나오겠지? 0.xxx만 나오기 때문에 범위를 지정해 놓으면 원하는 범위 내에서 난수를 생성해 낼 수 있다. 예를 들어 0에서부터 10까지 난수를 발생시키고 싶다면

int num = (int)(Math.random()*11);

이렇게 하면 된다. 절대 11이란 숫자는 나타나지 않는다. 왜그런지는 위에 내용을 참고 하면서 스스로 알아보는게 도움이 되겠다.

난수는 게임이나 예측불가능한 경우를 나타낼 때 자주 사용하기 때문에 잘 알아두도록 하자.

[Java] String

String의 불변성
String str1 = "abc";
String str2 = "abc";

같은 참조값을 가진다. 즉 하나의 "abc"를 함께 가리키는 꼴이다.

String 클래스 메소드에 대해 알아보자.
replace("C", "하드웨어"); C를 하드웨어로~
concat("입문"); 기존의 문자열 뒤에 입문을 추가~
length(); 문자열 길이 가져오기(null제외)
charAt(5); 주어진 위치(5)의 문자 하나를 반환
equlas(); 문자열 내용비교
substring(3, 7); 문자열 일부추출(3에서 7전까지)
trim(); 문자열의 앞뒤 공백 제거
tpUpperCase(); 소문자->대문자
toLowerCase(); 대문자->소문자
indexOf(문자열); 문자나 문자열이 기존의 문자열에 몇번째 존재하는지
endsWith(문자열);
startsWith(문자열); 해당 문자열로 시작하고 끝나는지 확인
getByte(); 문자열을 바이트 배열로 만들어 리턴한다. 파일을 만들 때 배열로 전달
toCharArray(); 문자열을 문자배열로 만들어 리턴한다.


StringBuffer와 StringBuilder의 가변성
버퍼를 가지고 있어 문자열을 조작할 수 있다. 여러 스레드가 동시에 하나의 버퍼를 조작하려 할때 데이터의 손상이가거나 교착상태에 빠질 수가 있다. StringBuffer는 그런 위험을 방지하는 장치가 존재하나 StringBuilder는 그런 장치가 없다. 대신에 스레드가 없는 일반 프로그램에서는 더 나은 성능을 발휘한다.

append(); 문자열 덧붙이기
insert( , ); Offset 위치에 문자열 삽입
delete( , ); 지정한 위치부터 지정한 위치까지 문자열 삭제
deleteCharAt(); 지정한 위치 문자삭제
capacity(); 버퍼크기 리턴
ensureCapacity(); 버퍼 늘리기
trimToSize(); 버퍼 줄이기


StringTokenizer 클래스
공백, 탭, 줄바꿈 문자, 캐리지 리턴 문자, 새페이지 문자를 기준으로 문자열을 나눈다.
hasmoreTokens();로 토큰이 존재하는지 확인후
NextToken();으로 토큰을 추출한다.

[Java] 익셉셥

자바에서는 미리 정의해둔 예외들이 존재한다.

생각해보자. 예외는 프로그램을 실행하여 작동할때 그 흐름에 있어서 프로그래머가 생각지 못한 예외는 꼭 존재하기 마련이다. 예를들어 어떤 수를 0으로 나눠버린다던지 등...

항상 사용자가 프로그래머가 의도한대로만 값을 넣고 결과를 유도하리라는 착각은 버려야 한다. 따라서 항상 예외가 날법한 곳에 예외처리를 해줘야하는 것은 귀찮은 일이 아니라 당연한 일이다.

그렇다면 자바에서는 어떻게 예외처리를 해줘야 할까?

1. try{
     ...
    }

 예외범위지정(즉, 예외가 일어날 부분만 지정)

2.catch(익셉션 종류 객체){
                  ...
   }
 예외처리

이 방법은 예외를 적극적으로 처리하는 방법이다. 예외가 발생하면 catch에서 바로 처리해주기 때문이다.

두 번째 방법은 예외를 회피하는 방식
throws Exception을 사용하여 메소드 밖으로 예외를 던지는 것을 말한다.
즉, 예외를 바로 처리하지 않고 밖으로 던져진 곳에서 처리하겠다는 의미이다.

예외는 분명 프로그램의 흐름을 방해하는 것이고 이를 항상 처리해줘야 하는 것은 프로그래머의 의무이다. 따라서 항상 API문서를 통해 해당하는 클래스의 상속, 생성자, 필드, 메소드만을 체크할 뿐만 아니라 throw 예외까지 보고 처리해 주도록 하자.

마지막으로
try{} catch{}에 이어서 finally{ }가 존재한다. finally블록은 try문에 명령이 시작되면 무조건 실행되는 것이 중요하다. finally에서는 예외가 발행하였든 하지 않았든 처리할 부분이 존재할 때 꼭 처리해주는 부분이다.

[Java] Object 클래스

오브젝트 클래스는 모든 클래스의 부모클래스!

오브젝트 클래스에는 toString(); equals(); 메소드가 정의 되어 있다.
따라서 모든 클래스에서 이 메소드들을 적절히 오버라이딩하여 재사용할 수 있음은 두말 나위 없다.

toString():
객체의 해쉬코드를 리턴(예: 객체이름@16진수코드)
equals();
주소값을 비교해 같은지 비교
clone();
객체의 복사(모든 객체를 복사할 수 있는 것이 아니라 clonable 인터페이스를 상속한 객체만 가능)
finalize();
객체가 제거되기 전에 자동으로 호출되는 메소드
getClass();
클래스 정보 출력(이클립스에서 Ctrl+Space를 누르면 목차가 뜨는 것이 이 클래스 덕분)

사용자 정의 클래스를 만들어 비교하고자 할때 목적에 맞게 재정의 해줘야한다.


[Java] 중첩, 네스티드, 로컬, 익명 클래스

중첩 클래스는 Outer클래스 객체 생성없이 Inner 클래스에서 단독적으로 객체를 생성되지 못한다. 즉, Outer클래스에 종속적이다. Outer클래스 안에 Inner클래스를 정의한다. 따라서 Outer에 있는 멤버와 메소드를 Inner에서 참조하거나 호출 가능하다.

정적내부클래스(네스티드 클래스)
많이 보는 클래스는 아니지만 Outer 클래스의 객체를 생성하지 않더라도 Inner클래스의 메소드를 사용할 수 있다. Outer클래스에 종속적이지 않고 단일 클래스로 취급하면서 클래스변수와 메소드를 호출할 수 있다.

로컬내부클래스
클래스가 메소드 내에 정의되어 있는 클래스이다. 메소드 안에서 클래스를 정의해 놓기 때문에 가독성이 좋다.

익명내부클래스(anonymous)
클래스의 선언부(시그너쳐)가 없다. 추상클래스와 인터페이스를 생성할 때 사용한다.
객체 생성과 동시에 {...}를 통해 명령부를 수행.

일반 클래스
class Myclass implements Interface{
                        .
                        .
                        .
}
Myclass obj1 = new Myclass();

익명내부클래스
public static void main(String[] args){
   Interface obj2 = new Interface(){
                        .
                        .
                        .
}
두개의 객체 obj1과 obj2는 같은 것이다!


즉, Interface를 implements한 class 객체를 생성하는 코드(혹은 추상 클래스를 상속한 class 객체를 생성하는 코드)와 익명 내부클래스에서 객체를 생성하는 코드는 같다.
차이는 익명내부클래스에서 만든 obj2는 한번만 만들어 사용할 것이고 객체 생성시 데이터를 전달하거나 리턴받지 못한다. 새로운 클래스를 다시 만들어 객체를 만들어 내기가 귀찮을 때 많이 사용한다. 그리고 인터페이스나 추상클래스는 객체를 생성하지 못하지만 이와 같은 방법으로 일시적으로 객체를 생성하여 활용할 수 있다는 장점이 있다.

2013년 1월 13일 일요일

[Java] class A extends B implement C{}

Object obj = new A();
    A     obj = new A();
    B     obj = new A();
    C     obj = new A();

알쥐? 모르면 진짜 바보

[Java] 인터페이스

인터페이스는 왜 써야 하는가???

기본적으로 자바에서는 클래스의 다중 상속을 막아놓았다. 그 이유는 분별없는 다중 상속은 객체들간의 관계를 복잡하게 만들게 되고 OOP(객체지향프로그래밍)에 있어서 좋지 못한 결과를 가져오기 때문이다.

다중 상속을 허용하지 않는 대신 자바에서는 인터페이스를 제공한다.

interface A {
  public abstract void B(){};
}

이렇게 구성되는데 항상 추상 메소드를 가지며 변수는 항상 공용 상수를 가진다.

인터페이스의 장점을 보면
1. 개발시간 단축
2. 표준화 가능
3. 서로 관계없는 클래스들에게 관계 부여
4. 독립적인 프로그래밍(1번의 연장선)

[Java] 오브젝트 형변환하는 이유!

계속해서 다형성에 대해 알아보자

많은 클래스들이 존재하고 클래스들 끼리의 관계를 형성하면서 프로그램을 구성하게 된다. 따라서 다양한 객체를 생성하고 그 객체들간의 관리의 필요성이 생겨나기 마련이다.
(생각해보라 무수히 많은 클래스로부터 생성된 객체들이 전혀 연관성이 없다면 어떻게 다 기억할 것이고 프로그램을 만들어 나갈 수 있을 것인가!!!)

 이렇듯 서로 다른 데이터형을 묶어줘야 할때, 즉 관리를 해야할 때 최소한 상속의 관계 또는   구현의 관계에 속해있는 객체들을 형변환하여 관리할 수 있다는 것은 프로그래머에게 굉장한 이득인 것이다!

2013년 1월 11일 금요일

[Java] 추상클래스

왜 사용될까?

public abstract class InputStream{}

이러한 추상 클래스가 있다.
InputStream이란 이름만 보면 왠지 입력과 출력에 관련된 클래스라고 느낄 수 있다.
그렇기에 당연히 입력과 출력에 관련된 함수들이 존재할 것이다.

실제로

abstract int read();

라는 메소드가 존재한다.

추상 클래스에를 상속하면 무조건 abstract(추상) 메소드를 오버라이딩하여 사용하여야한다. 부모 클래스의 이름을 보면 알수 있듯이 입출력과 관련된 부모클래스라면 이 클래스를 상속받는 자식클래스에도 부모가 가지고 있는 메소드를 오버라이딩 할수 밖에 없도록 제약을 가하면서 가이드라인을  만들어 놓은 것이다.

또한 추상클래스를 상속받아 오버라이딩해야 하기 때문에 추상 클래스의 객체를 만들어 사용할 수 없다. 즉, 추상클래스는 new 키워드로 객체를 생성할 수 없다.

[Java] 다형성

자바에 자료구조를 보면 ArrayList클래스가 존재한다.
이 클래스를 활용하여 어떤한 객체든 리스트로 만들어 관리할 수 있다.

여기서 중요한 것은 어떠한 객체라도 가능하다는 점이다.

자바에는 수많은 클래스로부터 생성된 객체가 많이 존재한다. 그런데 어떠한 객체도 관리가 가능하다는 것은 프로그래머로서는 상당히 유용한 점이다.

그렇다면 어떻게 그것이 가능할까???

String 클래스와 같은 자바에서 기본으로 제공하는 클래스뿐만 아니라 프로그래머가 정의한 클래스 등 모든 클래스는 Object클래스를 상속하는 관계에 있다. 즉 모든 클래스는 Object클래스의 자식 클래스인 것이다.

따라서 Object를 상속받은 모든 객체는 Object를 상속했다라는 하나의 공통점, 즉 같은 부모로부터 상속했고 Object클래스는 자식클래스를 자신의 클래스로 형변환하여 어떠한 객체의 주소값도 취할 수 있게 된다.
따라서 자신 뿐만아니라 상속관계의 자식 클래스까지 참조할 수 있고 이것이 다형성이라는 것이다.

잘 이해가 안되더라도 다음 한가지 사실을 기억하자!
자식은 부모가 되었다가 다시 자식이 된다.(자식은 자유자재로)
부모는 절대 자식이 되지 못한다.(부모는 항상 부모)


이러한 형변환은 실제 많이 일어난다. 따라서 어떤 객체의 형변환에 대해 알아보기 위해
instanceof 라는 키워드로 확인해보는 작업 또한 많이 한다.

Account obj = new Account();
obj instatnceof CheckingAccount

변환이 가능하면 true
불가능하면 false

[Java] 메소드 오버라이딩

상속시 부모의 메소드의 시그너처가 자식의 메소드와 같고 메소드의 몸체(내용)만 다르다.

그렇다면 왜 메소드의 시그너쳐를 같도록 할까?

자바의 다형성을 추구하기 위해서이다!
이 부분은 나중에 다형성에서 자세히 살펴보도록하자.

이렇게 부모의 메소드를 똑같이 자식클래스에 정의하여 내용부를 적절히 정의하는 것이
오버라이딩이다.

따라서 부모클래스에서 오버라이딩되는 메소드를 호출하면 부모클래스에 정의된 메소드가 호출되고 자식클래스 객체에서 같은 메소드를 호출하면 부모클래스에서 오버라이딩한 자신의 메소드를 호출한다.

즉, 오버라이딩하면 오버라이딩한 메소드가 호출된다.

2013년 1월 10일 목요일

[Java] 인터페이스

클래스는 생성할 객체들의 공통된 상태와 행동을 정의해 놓은 것이다. 그렇게 클래스를 정의하다보면 관련 클래스끼리의 공통된 기능이 존재할 연계성이 커진다.

그럴때 클래스끼리의 공통기능을 하나로 묶어 인터페이스를 정의할 수 있다. 그리고 인터페이스에 속하는 메소드는 무조건 추상(abstract) 메소드로 선언해야 한다.

또한 implements 한 클래스에서 인터페이스의 추상 메소드를 재정의 하기위해서는 반드시 메소드 앞에 public 키워드를 붙여야 한다.

[Java] abstract와 다형성

자바에서는 부모클래스 참조변수에 부모클래스로 만든 객체의 주소값뿐만 아니라 그 클래스의 자식클래스 객체도 대입할 수 있다.

즉 부모 클래스는 자식 클래스 객체를 모두 가리킬수 있다.
이것이 다형성이다! 이것은 아주 편리한 것이다!!! 배열뿐만 아니라 부모클래스를 선언해서 모든 자식을 가리키고 관리할 수 있기 때문이다!

또한 부모 클래스의 메소드의 이름과 타입형태를 자식 클래스에 똑같이 정해줄 수 있는 메소드 오버라이딩이 가능하다. 따라서 부모 클래스 객체를 생성해서 메소드를 호출하면 부모 클래스의 호출이 되고 자식 클래스 객체를 생성해서 같은 메소드를 호출하면 자식 클래스의 메소드를 호출한다.

abstract는 부모 클래스에서 정의해 놓으면 자식 클래스에서 반드시 부모 클래스의 abstract메소드를 재정의 해야만 하는데 이는 그 메소드를 반드시 구현하도록 만들기 위해서이다.

또한 abstract로 자식 클래스에서 재정의하면 부모클래스의 메소드를 호출하더라도 실제로는 자식클래스의 메소드가 호출되도록 한다,.

[Java] String

String 클래스에 문자열을 참조하는 참조변수를 만들면 절대 그 문자열을 바꿀 수 없다.
상수 클래스라고 하기도 한다.

문자열을 자주 사용할때 마다 객체가 생성되는데 너무 잦은 객체 생성은 프로그램의 성능을 낮춘다.

따라서 한번 만들어진 문자열은 같은 문자열의 String 객체를 생성한다면 같은 문자열을 가르킨다. 여러 String 객체가 동일한 문자열을 가르키게 되는 상황이 나타나기 때문에 절대 문자열을 변경할 수 없다. 참조만 가능하다.

이는 생성되는 객체의 수를 줄여 프로그램 성능을 높이기 위해서이다. 이를 위해 StringBuilder와 StringBuffer클래스가 존재한다.

이 두 클래스에 관해서는 다음에 정리하겠다.

2013년 1월 9일 수요일

[Java] 예외처리

코드상에서 에러를 처리 가능

try{
}
catch(){
}

문을 통한 예외 처리 try에서 에러가 발생하면 catch에서 해당하는 에러를 받아 처리할 수 있다.
메소드안에서

throw new Exception();

으로 예외를 처리할 객체 생성시키면
에러 발생시 catch(Exception e)에서 에러를 잡아 몸체를 실행한다.


[Java] 상속

상속으로 부모 클래스의 모든 상태와 행동, 즉 멤버변수와 메소드를 그대로 가진다.

extends 키워드 사용!

[Java] 배열복사 API

배열복사 API
System.arraycopy(scr, scr부터, des, des부터, 까지)

[이클립스] F3키의 유요성!

메소드 찾기!!! 다른 관련 클래스 모두에서 해당 메소드를 찾는다.

2013년 1월 8일 화요일

[Java] 클래스의 정적 구성 요소

클래스에 포함된 변수와 메소드 특징

1. 객체를 생성하지 않고도 사용할 수 있다.
2. 클래스이름.클래스변수
    로 호출한다.
3. 클래스를 실행할때 데이터 영역에 메모리에 할당(즉, 프로그램의 실행과 종료와 생명주기가 함께 한다.)
4. 공용변수로 사용할 수 있다.

final과 함께 공용상수로 사용가능하다
static 키워드의 변수나 메소드는 일반 멤버변수와 메소드를 사용할 수 없고 static끼리만 사용가능하다.

[Java] 접근자

접근제어자
변수, 메소드, 클래스 앞에서 붙일 수 있다.

private, default(아무것도 쓰지 않을 경우), protected, public

private : 같은 클래스 내에서만 접근 가능하다.
default : 해당하는 패키지(폴더) 내에서 접근 가능하다.
protected : 상속받는 클래스에서까지 접근 가능하다.
public : 제약없이 어디서든 접근 가능하다.


[Java] this() 생성자, this

this() 생성자

프로그램은 중복되는 코드를 싫어한다.

선언된 생성자가 여러개라면 중복되는 초기화 멤버값에 해당하는 생성자를 호출시켜줌으로써 초기화한다.

한마디로 생성자 안에서 생성자라고 생각하면 된다.


this

자기자신의 객체를 나타내는 문법

[Java] 클래스 내에 객체

클래스 안에서 다른 객체를 가질 수 있고 따라서 생성된 객체를 통해 멤버객체의 함수나 변수의 접근이 허용된다.

System.out.println();

이란 함수를 보자.

이 함수의 의미는 이렇다. System이란 클래스 내에 out이라는 객체를 멤버로 가지고 있다. 따라서 out 내에 println()함수를 System 객체를 이용하여 호출할 수 있는 것이다. 모든 클래스는 이렇게 독립적이지만 유기적으로 관계를 맺고 있고 이것을 잘 파악하고 활용하는 것이 자바 프로그래밍에서 중요하다.

[Java] 멤버변수와 지역변수의 차이

지역변수는 선언시 미리 초기화 하지 않으면 에러가 난다.
그러나 객체의 멤버변수는 미리 기본적인 값으로 초기화 되어 있다.

지역변수는 선언된 중괄호 안에서 생성되고 중괄호가 끝나면 메모리에서 삭제된다.
멤버변수는 객체가 생성되고 소멸할때 까지 삭제되지 않는다.

더이상 사용하지 않는 객체는 Garbage Collector에 의해 알아서 메모리 해제되므로 프로그래머는 신경써줄 필요 없다.(C/C++ 에 비해 메모리 유출로 인한 실수를 막아준다.)

[Java] 생성되는 모든 객체는 다르다!

객체를 생성하면 별도의 메모리를 할당하여 객체의 주소값으로 저장되기 때문에 모든 객체는 각기 다른 주소를 참조하는 객체가 된다.

2013년 1월 7일 월요일

[Java] 실무에서는,,,

실제 프로젝트에서는 고급개발자들이 프로젝트에 사용될 주요 메서드를 미리 작성하고, 이 들을 초중급 개발자들이 사용해서 개발하는 방식으로 프로젝트를 진행한다.

[Java] 생성자

객체를 초기화 하기 위한 목적.

객체를 생성할 때 자동으로 호출된다.
오버로딩이 가능하다.
리턴 타입이 없다.
생성자의 이름은 항상 클래스의 이름과 같다.

자바 API에 있는 클래스를 사용하여 객체를 생성할 때 생성자는 해당 API를 사용할 수 있는 가이드 라인이 된다.
즉, API의 특정 클래스의 생성자가 4가지면 객체를 만들 수 있는 방법이 4가지이다.

2013년 1월 6일 일요일

[Java] 객체와 클래스

OOP(Object Oriented Programming)

객체지향 : 현실세계를 모방하여 객체들의 상호작용을 통해 프로그래밍
(어떤 부모를 상속받을 수 있는지 생각해가면서 프로그래밍하는 것이 효율적이다.)

객체 : 어떤 상태와 행동으로 독립적으로 구별되는 대상

이러한 객체를 만들기 위한 추상화는 보는 사람의 관점에 따라 그 특성과 행동은 다르다.

클래스 : 개체들의 공통된 데이터 구조와 기능을 정의해 놓은 것(객체 모양으로 틀을 만든 것)

즉, 객체와 클래스의 관계는 붕어빵과 붕어빵 틀의 관계와 같다.

객체를 생성하면 객체의 멤버변수와 메소드를 가지게 된다.

객체 생성시 별도의 메모리가 할당. 그 메모리의 주소값을 객체의 이름이 가지고 있다.
객체는 레퍼런스 변수이기 때문이다.

[Java] 버퍼비우기

Scanner 클래스를 이용하여 입력을 받을 때 버퍼에 남은 데이터를 비워야 하는 경우가 있다.

이럴때 sc.nextLine()함수를 사용하면 버퍼를 비울 수가 있다.

[Java] 클래스의 public과 default

어떤 하나의 특정한 기능을 하는 클래스들의 묶음을 라이브러리 형태로 가지고 있고 이 라이브러리를 활용하여 프로그램을 개발할 수 있다.

그런데 라이브러리를 활용하는 측면에서 라이브러리를 구성하는 모든 클래스의 기능을 파악하고 활용하기란 쉬운일이 아니다. 그리고 라이브러리 안에 모든 클래스가 다 중요하지만은 않다. 때문에 외부에서 접근할 수 있는 메인 클래스, 즉 출입할 수 있는 클래스를 메인으로 디자인 하여 그 메인 클래스만을 활용함으로써 라이브러리의 모든 기능을 구현할 수 있도록 되어있다. 그 메인 클래스에 public 키워드를 붙여 놓음으로써 언제든지 외부에서 특정한 라이브러리의 기능을 활용할 수 있는 것이다.

그리고 메인 클래스를 제외한 나머지 클래스들은 default로 만들어 관계된 클래스끼리의 호출이 가능하고 외부에서는 접근을 하지 못하게 해 놓는 것이다. 이것이 객체지향 패러다임에 굉장히 중요하고 왜 객체지향을 선호하는지의 중요한 이유 중 하나일 것이다.

[Java] 클래스 패스와 패키지

각각 따로 만들어진 클래스의 이름이 같은 경우가 발생했을 때 이 클래스간의 구별이 필요하게 된다. 따라서 패키지라는 개념이 등장하게 되는 것이다.

인스턴스 생성시 디렉토리에 따라 이름이 같은 클래스라 할지라도 구분할 수가 있게 된다.
이런 패키지의 개념 이전에 먼저 고려해야 할 것이 바로 클래스 패스이다.

클래스 패스는 보통 자바를 설치하고 환경변수를 지정하면서 설정하게 되는데 이렇게 해놓게 되면 자바를 공부하는 데에는 문제가 없지만 실무에서 많은 컴퓨터 시스템에 자바실행 환경을 설정할 때에 여간 번거로운 작업이 아닐수 없다.

따라서 명령 프롬프트 창에서 클래스패스를 설정하고 배치파일을 유포하는 것이 훨씬 수월하다.

클래스 패스를 설정한 디렉토리는 시작을 나타내는 디렉토리 경로를 의미하게 되고 그 경로 안에 패키지를 설정해 줌으로써 클래스간의 구별이 가능해 질 뿐만 아니라 JVM이 클래스 패스를 이용하여 필요한 클래스를 찾아갈 수 있도록 해준다,

2013년 1월 2일 수요일

[Java] 프로그램의 기본

자바 뿐만 아니라 보통의 프로그램이란 것은 가장 작은 단위로 변수와 함수로 이루어져 있다.

하지만 자바에서는 변수를 필드라고 말하기도 하고 함수를 메소드라 부른다. 이러한 소소한 차이 말고는 프로그램을 구성하는데 큰 차이점은 없다.

그러나 자바가 추구하는 객체지향이라는 개념이 좀 더 코드의 재사용과 확장성에 큰 도움을 준다.

다시말해 변수와 메소드가 하나의 객체를 구성하는데 이 객체를 가지고 갖가지 기능을 사용할 수 있다. 그러나 그 객체는 클래스라는 것을 통해 목적에 맞게 생성하여 사용할 수 있다. 따라서 규모가 큰 프로그램의 경우 클래스를 프로그램의 가장 작은 프로그램 구성요소라고 한다.

그러한 클래스들의 집합을 패키지라고 부르며 관련된 기능들의 집합들을 모아놓은 것이라 생각된다. 마지막으로 이러한 각각의 관련 기능들의 집합인 패키지가 더해지고 합쳐져서 하나의 어플리케이션이 된다.

---------------------------------------------------------------------------------

여기까지가 단지 클래스의 개념만 조금 아는 내가 설명을 듣고 정리해본 것이다. 이 생각이 옳을지 아닐지는 더 배워 나가야 할 것이다. 열심히 하자. 아자.

[Java] 향상된 for문

배열을 사용할 때 사용가능한 for문이다.

int arr[] = {1,2,3,4,5};

for(int num : arr){
   System.out.println(num);
}

이렇게 하면 배열에 저장된 정수 하나하나를 출력할 수 있다. 즉 굳이 배열의 범위를 명시하지 않아도 알아서 배열의 길이만큼 데이터 관리가 가능하다. 주의할 점은 int형 배열이라면 int형 변수를 for문 조건에 적용해야한다.

2013년 1월 1일 화요일

[Java] 배열

여러개의 동일한 데이터 형 변수들의 집합

java.lang.ArrayIndexOutOfBoundsException

과 같은 에러가 나타나면 배열의 범위를 넘어서 메모리에 값을 읽거나 저장하려 했다고 경고하는 에러창이다.

상수를 가지고 다양한 값을 이용하여 프로그래밍하기 위해 변수라는 것이 생겼고 그 변수를 여러개 이용하여 많은 데이터를 관리하기 위해 배열이 생겨났다.
 그리고 그 배열이 가지고 있는 한계(동일자료형의 데이터만 관리)를 극복하기 위해 객체라는 개념이 생겼고 그 객체를 잘 관리하기 위해 자료구조가 생겨나는 것이다.


[Java] 중첩된 반복문 break, continue

for문에는 for문의 이름을 붙여 줄 수 있는 라벨이라는 개념이 존재한다.

따라서 라벨의 이름의 for문을 break, continue하면 해당하는 for문에 대한 적절한 처리가 가능하다.


public class Exam04 {

public static void main(String[] args) {

outerLoop:
for(int row=0; row<3; row++){
for(int col=0; col<5; col++){
System.out.println(row + "," + col);
if((row==1)&&(col==3))
break outerLoop;
}
}
}

}

[Java] 조건문과 반복문

조건문과 반복문이 어떻게 구성되어 있는지에 관해서는 쓰지 않겠다. 다만 왜? 무엇때문에 쓰는지 그 이유에 대해 설명할 수 있어야 하겠다.

조건문은 조건에 따라서 실행되어야 할 부분과 실행되지 않아야 하는 로직을 구성하기 위해 사용되며 if, if~else, switch 문이 있다.

반복문은 해야할 일이 많을 때 사용하며 while, do~while, for 문이 있다.