간만에 자바 포스팅.. ㅋ

졸업작품 관련해서 스크린 캡쳐하는 모듈을 간단하게 구현하여 보았다.

자바를 이용해서 스크린 캡쳐라든지, 마우스, 키보드 제어 같은 저수준의 동작들을

네트워크를 통해서 제어할 수 있느냐가

이번 졸작의 핵심사항인데.. 과연 성공할 수 있을지 흥미진진.

우선 스크린 캡쳐 코드.

package capture;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import com.sun.image.codec.jpeg.*;

public class Main extends JPanel implements Runnable, ActionListener {

    JButton btn_capture;
    Image img = null;

    // 생성자. UI 배치.
    public Main() {
        this.btn_capture = new JButton("영상캡쳐");
        this.btn_capture.addActionListener(this);
        this.setLayout(new BorderLayout());
        this.add(this.btn_capture, BorderLayout.SOUTH);
    }

    public void actionPerformed(ActionEvent e) {
        String cmd = e.getActionCommand();
        if (cmd.equals("영상캡쳐")) {
            System.out.println("영상을 캡쳐합니다..");
            this.capture();                     // 영상캡처 버튼이 눌리면 캡쳐.
        }
    }

    private void drawImage(Image img, int x, int y) {
        Graphics g = this.getGraphics();
        g.drawImage(img, 0, 0, x, y, this);
        this.paint(g);
        this.repaint();
    }

    public void paint(Graphics g) {
        if (this.img != null) {
            g.drawImage(this.img, 0, 0, this.img.getWidth(this), this.img.getHeight(this), this);
        }
    }

    public void capture() {
        Robot robot;
        BufferedImage bufImage = null;
        try {
            robot = new Robot();
            Rectangle area = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());

            bufImage = robot.createScreenCapture(area);     // Robot 클래스를 이용하여 스크린 캡쳐.

            //Graphics2D g2d = bufImage.createGraphics();
            int w = this.getWidth();
            int h = this.getHeight();

            this.img = bufImage.getScaledInstance(w, h - 20, Image.SCALE_DEFAULT);
            //this.repaint();
            this.drawImage(img, w, h);
            saveJPEGfile("cap.jpg", bufImage);              // JPG 파일로 변환하여 저장.
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static boolean saveJPEGfile(String filename, BufferedImage bi) {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(filename);
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bi);
            param.setQuality(1.0f, false);
            encoder.setJPEGEncodeParam(param);

            encoder.encode(bi);
            out.close();
        } catch (Exception ex) {
            System.out.println("Error saving JPEG : " + ex.getMessage());
            return false;
        }
        return true;
    }

    public void run() {
        while (true) {
            this.setBackground(Color.RED);
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
            }
            this.setBackground(Color.GREEN);

            try {
                Thread.sleep(1000);
            } catch (Exception e) {
            }
        }

    }

    public static void createFrame() {
        JFrame frame = new JFrame("Jv");
        JFrame.setDefaultLookAndFeelDecorated(true);
        Container cont = frame.getContentPane();
        cont.setLayout(new BorderLayout());
        Main mm = new Main();
        //new Thread(mm).start();
        cont.add(mm, BorderLayout.CENTER);

        frame.setSize(400, 400);
        frame.setVisible(true);
    }

    public static void main(String... v) {
        //new Main();
        JFrame.setDefaultLookAndFeelDecorated(true);
        createFrame();
    }
}


이 코드의 핵심은 바로 이곳.
robot = new Robot();
Rectangle area = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
bufImage = robot.createScreenCapture(area);     // Robot 클래스를 이용하여 스크린 캡쳐.

Robot 클래스를 생성하고, 현재 화면의 사이즈를 Rectangle 클래스로 받아 createScreenCapture 메소드의 인자로 넘기면 BufferedImage 인스턴스를 리턴하여 이미지를 얻을수 있다.

다음은 실행화면.

사용자 삽입 이미지


바탕화면을 캡쳐한것이 Panel의 Center에 위치하게 된다.
또한 이 이미지는 JPG 파일로 변환되어 저장되게 된다.(saveJPEGfile 메소드)

참고로 Robot 클래스는 1.3 부터 기본으로 자바에 포함되어 배포되고 있으며 JavaDoc에 설명이 자세하게 되어 있다. 궁금하면 찾아보도록 ㅎㅎ

여기는 Robot 클래스를 잘 설명해놓은 사이트.

출처 : http://semtle.tistory.com  셈틀쟁님이의 블로그
Posted by 행복한 프로그래머 궁금쟁이박

댓글을 달아 주세요

  1. 2011.03.29 23:01  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

자바에서는 크게 다음 세 가지의 입출력을 다룬다.

1. 1 byte 단위 입출력
2. 2 byte 단위 입출력
3. 객체 단위 입출력


  • 1 byte 출력

콘솔 출력용
FileOutputStream fos = new FileOutputStream(FileDescriptor.out);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream dos = new DataOutputStream(bos);
dos.write...


파일 출력용
File file = new File("파일명");
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream dos = new DataOutputStream(bos);
dos.write...


네트워크 출력용
Socket soc = new Socket(..);
BufferedOutputStream bos = new BufferedOutputStream(soc.getOutputStream());
DataOutputStream dos = new DataOutputStream(bos);
dos.write...


  • 1 byte 입력

콘솔 입력용
FileInputStream fis = new FileInputStream(FileDescriptor.in);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
dos.write...


파일 입력용
File file = new File("파일명");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
dos.write...


네트워크 입력용
Socket soc = new Socket(..);
BufferedInputStream bis = new BufferedInputStream(soc.getInputStream());
DataInputStream dis = new DataInputStream(bis);
dos.write...


  • 2 byte 출력

콘솔 출력용
OutputStreamWriter osw = new OutputStreamWriter(System.out);
BufferedWriter bw = new BufferedWriter(osw);
PrintWriter pw = new PrintWriter(bw);
pw.println(..);


파일 출력용
File file = new File("파일명");
FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw);
PrintWriter pw = new PrintWriter(bw);
pw.println(...);


네트워크 출력용
Socket soc = new Socket(..);
OutputStreamWriter osw = new OutputStreamWriter(soc.getOutputStream());
BufferedWriter bw = new BufferedWriter(osw);
PrintWriter pw = new PrintWriter(bw);
pw.println(..);


  • 2 byte 입력

콘솔 입력용
InputStreamReader isr = new InputStreamReader(System.out);
BufferedReader br = new BufferedReader(isr);
br.readLine();


파일 입력용
File file = new File("파일명");
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
br.readLine();


네트워크 입력용
Socket soc = new Socket(..);
InputStreamReader isr = new InputStreamReader(soc.getInputStream());
BufferedReader br = new BufferedReader(isr);
br.readLine();


 

  • 객체 출력

파일 출력용
File file = new File("파일명");
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(...);


네트워크 출력용
Socket soc = new Socket(..);
BufferedOutputStream bos = new BufferedOutputStream(soc.getOutputStream());
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(...);



  • 객체 입력

파일 입력용
File file = new File("파일명");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
ObjectInputStream ois = new ObjectInputStream(bis);
try {
 Object obj = ois.readObject();
}
catch(ClassNotFoundException ee){}


네트워크 입력용
Socket soc = new Socket(..);
BufferedInputStream bis = new BufferedInputStream(soc.getInputStream());
ObjectInputStream ois = new ObjectInputStream(bis);
try {
 Object obj = ois.readObject();
}
catch(ClassNotFoundException ee){}

Posted by 행복한 프로그래머 궁금쟁이박
TAG I/O, Java, 자바

댓글을 달아 주세요

사용자 삽입 이미지

MVC 를 철저히 구현한 스윙 컴포넌트 한번에 보기
Posted by 행복한 프로그래머 궁금쟁이박

댓글을 달아 주세요

JDK 에서 가장 많이 쓰이는 패턴 중 하나인 옵저버(Observer) 패턴에 대해 설명한다.

헤드퍼스트 디자인 패턴 책 참고^^

날씨를 디스플레이해주는 기상 모니터링 애플리케이션 개발을 예로 들었다.

이 애플리케이션은 크게 기상 스테이션, Weather Data 객체, 디스플레이 객체

세 요소로 이루어진다.

WeatherData 클래스이다.

WeatherData :

getTemperature()

getHumidity()

getPressure()

measurementsChanged()

위의 세가지 게터메소드는 각각 최근에 측정된 온도, 습도, 기압 값을 리턴하는 메소드이다.

measurementsChanged 메소드는 기상 관측값이 갱신될 때마다 알려주기 위한 메소드이다.

WeatherData 객체를 개발한 사람들이 우리가 추가해야 할 부분에 대한 힌트를 남겨준 것이다.

우리는 이 메소드를 현재 조건, 기상통계, 기상예측 세가지 디스플레이를 갱신할 수 있도록

구현해야 한다.

또한 시스템이 확장 가능해야한다. 다른 개발자들이 별도의 디스플레이 항목을 만들 수 있도록 해야 하고

사용자들이 애플리케이션에 마음대로 디스플레이 항목을 추가/제거할 수 있도록 해야한다.

다음은 대강 구현해 본 measurementsChanged 메소드이다.

public class WeatherData {

       // 인스턴스 변수 선언

       public void meaasurementsChanged() {

                  float temp = getTemperature();
                  float humidity = getHumidity();
                  float pressure = getPressure();

                  // 디스플레이 갱신
                  curentConditionsDisplay.update(temp, humidity, pressure);
                  statisticsDisplay.update(temp, humidity, pressure);
                  forecastDisplay.update(temp, humidity, pressure);
         }
  
         // 기타 메소드

}

이 코드에는 문제가 있다.

구체적인 구현에 맞춰서 코딩했기 때문에 프로그램을 고치지 않고는 다른 디스플레이 항목을

추가/제거할 수 없는 것이다.

출판사 + 구독자 = 옵저버 패턴

이러한 신문 구독 메커니즘을 제대로 이해한다면 옵저버 패턴을 쉽게 이해할 수 있다.

출판사를 주제(subject), 구독자를 옵저버(observer) 라고 부른다는 것을 외워두자.

주제 객체에서는 일부 데이터를 관리한다.

옵저버 객체들은 주제 객체를 구독하고 있으며 ( 주제 객체에 등록되어 있으며 ) 주제의

데이터가 바뀌면 갱신 내용을 전달 받는다.

Duck 이라는 객체는 옵저버가 되기를 원한다. 주제객체에개 자기도 옵저버가 되고싶다고 이야기하고,

공식적인 옵저버가 된다. 이제 주제 객체의 값이 바뀌면 Duck 을 비롯한 모든 옵저버들이 주제 객체의 값이

바뀌었다는 연락을 받게 된다.

Mouse 라는 객체는 옵저버 목록에서 탈퇴하고 싶다는 요청을한다. 그러면 주제 객체에서 Mouse 의 요청을

받아들여 옵저버 집합에서 제거시킨다. 주제 객체게 또 새로운 값이 들어오면 이제 Mouse 한테는

연락이 되지 않는다.

그렇다면 옵저버 패턴의 정확한 정의를 알아보자

옵저버 패턴(Observer Pattern) 에서는 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한

테 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one-to_many) 의존성을 정의한다.


옵저버 패턴을 구현하는 방법에는 여러 가지가 있지만, 대부분 주제(Subject) 인터페이스와 옵저버(Observer)

인터페이스가 들어있는 클래스 디자인을 바탕으로 한다.

다음은 옵저버 패턴 다이어그램이다.


사용자 삽입 이미지

이 다이어그램과 인대다 관계는 무슨 관계가 있는가?

- 옵저버 패턴에서 상태를 저장하고 지배하는 것은 주제 객체이다. 따라서 상태가 들어있는 객체는 하나만

있을 수 있다. 하지만 옵저버는 사용하긴 하지만 반드시 상태를 가지고 있어야 하는 것은 아니다. 따라서

옵저버는 여러 개가 있을 수 있으며, 주제 객체에서 상태가 바뀌었다는 것을 알려주기를 기다리는, 주제에

의존적인 성질을 가지게 되는 것이다. 그러므로 하나의 주제와 여러 개의 옵저버가 연관된, 일대다 관계가

성립되는 것이다.

의존성과는 무슨 상관이 있나?

- 데이터의 주인은 주제(Subject) 이다. 옵저버는 데이터가 변경되었을 때 주제에서 갱신해 주기를 기다리는

입장이기 때문에 의존성을 가진다고 할 수 있다. 이런 방법을 사용하면 여러 객체에서 동일단 데이터를 제어하

도록 하는 것에 비해 더 깔끔한 객체지향 디자인을 만들 수 있게 된다.

디자인의 원칙 중에는 이러한 것이 있다.

"서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 ( Loose coupling ) 디자인을

사용해야 한다."


옵저버 패턴에서는 주제와 옵저버가 느슨하게 결합되어 있는 객체 디자인을 제공한다.

주제와 옵저버는 서로 독립적으로 재사용할 수 있다. 주제나 옵저버를 다른 용도로 활용할 일이 있다고

해도 손쉽게 재사용할 수 있다. 그 둘이 서로 단단하게 결합되어 있지 않기 때문이다.

주제나 옵저버가 바뀌더라도 서로한테 영향을 미치지는 않는다. 둘이 서로 느슨하게 결합되어 있기

때문에 주제 혹은 옵저버 인터페이스를 구현한다는 조건만 만족된다면 어떻게 바꿔도 문제가 생기는

일은 없는 것이다.

느슨하게 결합하는 디자인을 사용하면 객체 사이의 상호 의존성을 최소화할 수 있기 때문에 변경사항

이 겨도 무난히 처리할 수 있는 유연한 객체지향 시스템을 구축할 수 있게 된다!.

다음은 기상 스테이션의 다이어그램 설계이다.

사용자 삽입 이미지

이 다이어그램을 바탕으로 코드를 만들어 보자.

public interface Subject {

         public void registerObserver(Observer o);     // 옵저버를 등록
         public void removeObserver(Observer o);     // 옵저버를 제거
         public void notifyObservers();  // 주제 객체의 상태가 변경되었을 때 모든 옵저버들에게 알리는 메소드
}

public interface Observer {
          // Observer 인터페이스는 모든 옵저버 클래스에서 구현해야 한다.
          // 따라서 모든 옵저버는 update() 메소드를 구현해야 한다.
          public void update(float temp, float humidity, float pressure);

}

public interface DisplayElement {
          // display() 메소드 하나만 갖는다. 디스플레이 항목을 화면에 표시해야 하는 경우 호출한다.
          public void display();

}

WeatherData 에서 Subject 인터페이스 구현하기

public class WeatherData implements Subject {
 
 private ArrayList observers;
 private float temperatures;
 private float humidity;
 private float pressure;
 
 public WeatherData() {
  observers = new ArrayList();
 }
 
 public void registerObserver(Observer o) {
  observers.add(o);
 }
 
 public void removeObserver(Observer o) {
  int i = observers.indexOf(o);
  if(i >= 0) {
   observers.remove(i);
  }
 }
 
 /*
  * 상태에 대해 모든 옵저버들한테 알려주는 부분
  * 모두 Observer 인터페이스를 구현하는, 즉 update() 메소드가 있는
  * 객체들이므로 손쉽게 알려줄 수 있습니다.
  */
 public void notifyObservers() {
  for(int i = 0 ; i < observers.size() ; i++) {
   Observer observer = (Observer)observers.get(i);
   observer.update(temperatures, humidity, pressure);
  }
 }
 
 /*
  * 기상 스테이션으로부터 갱신된 측정치를 받으면 옵저버들한테 알립니다.
  */
 public void measurementsChanged() {
  notifyObservers();
 }
 
 public void setMeasurements(float temperature, float humidity, float pressure) {
  this.temperatures = temperature;
  this.humidity = humidity;
  this.pressure = pressure;
  measurementsChanged();
 }
}

디스플에이 항목 만들기


public class CurrentConditionsDisplay implements Observer, DisplayElement {
 
 private float temperature;
 private float humidity;
 private Subject weatherData;
 
 
 /**
  * 생성자에 weatherData 라는 주제 객체가 전달되며,
  * 그 객체를 써서 디스플레이를
  * 옵저버로 등록한다.
  */
 public CurrentConditionsDisplay(Subject weatherData) {
  this.weatherData = weatherData;
  weatherData.registerObserver(this);
 }
 
 public void update(float temperature, float humidity, float pressure) {
  this.temperature = temperature;
  this.humidity = humidity;
  display();
 }
 
 public void display() {
  System.out.println("Current conditions: " + temperature +
    "F degrees and " + humidity + " % humidity");
 }
}

테스트용 기상 스테이션 클래스


public class WeatherStation {

 public static void main(String [] args) {
  WeatherData weatherData = new WeatherData();
 
  CurrentConditionsDisplay currentDisplay =
   new CurrentConditionsDisplay(weatherData);
 
 // 코드 생성해야 함
 // StatisticsDisplay statisticsDisplay =
 //  new StatisticsDisplay(weatherData);
 // ForecastDisplay forecastDisplay =
 //    new ForecastDisplay(weatherData);
 
  // 새로운 기상 측정 값이 들어왔다고 가정
  weatherData.setMeasurements(80, 65, 30.4f);
  weatherData.setMeasurements(82, 60, 26.2f);
  weatherData.setMeasurements(78, 90, 29.3f);
 
 }
}

이제 주제 객체와 옵저버가 직접 대화를 하고 있게 되었다.

옵저버들이 Observer 인터페이스를 구현하고 있기 때문인 것이다.

이러한 옵저버 패턴은 사실 자바에 내장되어있다.

java.util 패키지에 들어있는 Observer 인터페이스와 Observable 클래스가 그것이다.

다음은 자바 내장 기능을 활용한 기상 스테이션 구현 코드이다.


import java.util.*;

public class WeatherDataExt extends Observable { // Observable 의 서브클래스
 
 private float temperature;
 private float humidity;
 private float pressure;
 
 public WeatherDataExt() {
  // 이제 생성자에서 옵저버들을 저장하기 위한 자료구조를 만들 필요가 없다.
 }
 
 public void measurementsChanged() {
  setChanged(); // 상태가 바뀌었다는 것을 알린다.
  notifyObservers();
 }
 
 public void setMeasurements(float temperature, float humidity, float pressure) {
  this.temperature = temperature;
  this.humidity = humidity;
  this.pressure = pressure;
  measurementsChanged();
 }

 
 //
 // 옵저버가 WeatherData 객체의 상태를 알아낼 때는 이 메소드를 사용한다.
 //
 public float getTemperature() {
  return temperature;
 }

 public float getHumidity() {
  return humidity;
 }

 public float getPressure() {
  return pressure;
 }
}

import java.util.*;

public class CurrentConditionsDisplayExt implements Observer, DisplayElement {

 Observable observable;
 private float temperature;
 private float humidity;
 
 public CurrentConditionsDisplayExt(Observable observable) {
  this.observable = observable;
  observable.addObserver(this);
 }
 
 public void update(Observable obs, Object arg) {
  if(obs instanceof WeatherDataExt) {
   WeatherDataExt weatherData = (WeatherDataExt)obs;
   this.temperature = weatherData.getTemperature();
   this.humidity = weatherData.getHumidity();
   display();
  }
 }
 
 public void display() {
  System.out.println("Current conditions : " +
    temperature + "F degrees and " + humidity + "% humidity");
 }
}

이번에는 java.util.Observable 의 단점에 대해 알아본다.

Observable 은 인터페이스가 아닌 클래스인 데다가, 어떤 인터페이스를 구현하는 것도 아니다.

안타깝게도 활용도와 재사용성에 있어서 제약조건으로 작용하는 몇 가지 문제점이 있다.

Observable 은 클래스이다.

Observable 이 클래스이기 때문에 서브클래스를 만들어야 한다는 점이 문제가 된다.

이미 다른 수퍼클래스를 확장하고 있는 클래스에 Observable 의 기능을 추가할 수 없기 때문이다.

그래서 재사용성에 제약이 생기게 되는 것이다.

또한 Observable 인터페이스라는 것이 없기 때문에 자바에 내장된 Observer API 하고 잘 맞는 클래스를

직접 구현하는 것이 불가능하다. java.util 구현을 다른 구현으로 바꾸는 것도 불가능하다.

그렇다면 어떻게 해야 할까?

java.util.Observable 을 확장한 클래스를 쓸 수 있는 상황이라면 Observable API 를 쓰는 것도 괜찮을

것이다. 하지만 앞에서 했던 것처럼 직접 구현할 수도 있다. 둘 중 어떤 방법을 쓰든 옵저버 패턴만 제대로

알고있다면 그 패턴을 활용하는 API 는 어떤 것이든 잘 활용할 수 있을 것이다.

Posted by 행복한 프로그래머 궁금쟁이박

댓글을 달아 주세요

  1. BlogIcon replica watches 2013.01.22 16:56  댓글주소  수정/삭제  댓글쓰기

    난 여기 이렇게 다른 사람들이 읽을 수에 내 사이트로 연결되는 링크를 넣어. 내 독자에 대한 같은 행복합니다.

mysql.org 에서 먼저 DB 와 GUI 툴 정도를 다운받아 설치한다.

MySQL Community Server 에서 버전을 선택하여 다운받아 설치하면 된다.

또한 GUI Tools 도 알맞은 버전을 다운받아 설치한다.

설치과정은 생략^^;

mysql connector 은 mysql tools 디렉토리에 첨부되어있으니 프로젝트 라이브러리에 add 시켜야한다.

샘플 테이블을 만든 뒤 mysql 을 연동하는 프로그램을 만들어 보았다.


package prj_jdbc;
import java.sql.*;
/**
 *
 * @author 컴퓨터과학부
 */
public class HelloJDBC {

    String id, pwd;
   
    public HelloJDBC(String id, String pwd) {
        this.id = id;
        this.pwd = pwd;
        try {
            Class.forName("org.gjt.mm.mysql.Driver").newInstance();
                             
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
   
    public void getData() {
        try {
            String url = "jdbc:mysql://localhost:3306/contacts";
            String option = "?useUnicode=true&characterEncoding=KSC5601";
            url = url + option;
            Connection con = DriverManager.getConnection(url, id, pwd);
            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery("select * from friends");
            while(rs.next()) {
                String name = rs.getString(1);
                String phone = rs.getString(2);
                String email = rs.getString(3);
                String company = rs.getString(4);
               
                System.out.println(name + " \t | " + phone + "\t | " + email + "\t | " + company);
            }
            rs.close();
            stmt.close();
            con.close();
        }
        catch(Exception ex) {
            ex.printStackTrace();
        }
    }
   
    public static void main(String [] args) {
        HelloJDBC hj = new HelloJDBC("root", "root");
        hj.getData();
    }
}
   
   

   

Posted by 행복한 프로그래머 궁금쟁이박
TAG Java, JDBC, MySQL

댓글을 달아 주세요

HashMap에서 값을 꺼내기 위해서 보통 get 매소드를 이용하여 key값에 해당하는 value를 얻는다.


key값을 모르는 상태에서 HashMap에 저장된 모든 key와 그에 대응되는 value를 얻고자 할 때 다음과 같이 하면 된다.




[ HashMap 예제 ]

  1. import java.util.HashMap;
  2. import java.util.Iterator;
  3. import java.util.Map.Entry;
  4. public class HashMapTest {
  5.   public static void main(String[] args) {
  6.     HashMap map = new HashMap();
  7.     map.put("first", "First String");
  8.     map.put("second", "Second String");
  9.     Iterator iterator = map.entrySet().iterator();
  10.     while (iterator.hasNext()) {
  11.       Entry entry = (Entry) iterator.next();
  12.       System.out.println("key : " + entry.getKey() + "    value : "
  13.           + entry.getValue());
  14.     }
  15.   }
  16. }

결과 )

key : first    value : First String

key : second    value : Second String

HashMap에 값이 저장될 때 내부적으로 HashMap의 inner class로 구현된 Entry라는 클래스의 인스턴스로 저장된다.

Posted by 행복한 프로그래머 궁금쟁이박
TAG Java

댓글을 달아 주세요

추상클래스
인터페이스
공통점

  • 모두 클래스임
  • 하위클래스에서 모든 추상메서드를 구현해야 함
차이점

  • 추상메서드 외 일반 멤버 변수와 메서드를 가질 수 있다.
  • extends를 사용
  • 단일 상속만 가능
  • 작업의 레벨 분할을 위해서 사용

  • 추상메서드와 static final 변수만 사용
  • Implements를 사용
  • 중복 구현 가능
  • 공동 작업을 위한 상호간의 인터페이스를 위해 사용
 
클래스는 크게 일반클래스와 추상클래스로 나뉘는데 추상클래스는 본문중에 '추상메소드'가 하나 이상 포함되는 경우를 말합니다.
 
인터페이스는 모든 메소드가 추상메소드인 경우 선언하는 경우가 많습니다.
추상메소드라 함은 메소드의 선언부만 있고 본문이 없는 것을 말합니다.
여기서 본문은 중괄호({})로 묶여진 몸체(body)부분을 말하는데 중괄호 안이 비어있더라도 이것이 존재한다면 그것은 추상메소드가 아닙니다.
추상메소드의 선언의 예는 다음과 같습니다.
abstract public void test( int a );
 
즉, 메소드의 선언 후에 세미콜른(;)만을 찍어 이를 선언만 하고 구현은 자식클래스에서 하게 하는 방법입니다.
 
일반 클래스의 경우 상속받은 자식클래스가 반드시 부모클래스의 메소드를 '오버라이딩(overriding)'할 필요가 없지만 추상클래스를 상속받은 자식클래스는 반드시 추상메소드를 오버라이딩하여야 하기에 메소드를 강제로 구현하게 할 때 많이 쓰입니다.
추상클래스와 인터페이스의 가장 큰 차이점은 바로 '클래스'냐 아니냐의 차이입니다. 추상클래스는 엄연한 클래스로 이를 구현하는 것은 '상속(extends)'입니다.
그러나 인터페이스는 '구현(implements)'라는 키워드를 통해 구현하게 되는데 이는 자바에서 매우 중요한 차이를 가집니다.
 
자바는 오로지 '단일 상속'만을 지원하기 때문에 추상클래스를 상속받는 클래스는 다른 클래스를 상속받을 수 없습니다.
그러나 인터페이스를 포함하는 클래스는 다른 클래스를 상속받을 수 있습니다.
 
추상클래스는 일반클래스와 달리 그 자신을 new 명령어를 통해 객체를 생성할 수 없습니다. 그러나 '다형성(polymorlphism)'을 통해 자식 클래스의 객체를 생성할 수는 있습니다.
 
인터페이스를 쓰는 가장 큰 이유는 다중상속을 지원하지 않는 자바에서 다중상속의 장점을 가져오기 위해서입니다.
다중상속이 가지는 단점은 배제하고 오직 장점만을 취하기 위해 인터페이스를 쓰는 것입니다.

* 토달기를 봅시다.
 
상속이란 개념은 부모클래스의 속성과 메소드를 자식클래스가 물려받는다는 것인데 쉽게 예를 들면 '자동차'라는 클래스는 '색깔', '배기량' 등의 속성과 '기름을 넣는다', '달린다' 등의 메소드를 가질 수 있습니다. 이 클래스를 상속하는 '승용차' 클래스는 별도로 선언하지 않아도 부모클래스의 '색깔', '배기량'이라는 속성과 '기름을 넣는다', '달린다'라는 메소드를 가지게 되죠.
 
추상클래스는 이 부모클래스가 단순히 관념적인 성격이 강할 때 많이 쓰이는데 예컨데 '새'라는 클래스는 그냥 '난다'라는 메소드를 가지지만 새의 종류에 따라 나는 방법이 조금씩 틀려 자식클래스에서 어차피 구현해야 될 부분이므로 굳이 부모클래스에서 그 내용을 구현할 필요가 없기 때문에 사용합니다.
 
요사이 추세는 굳이 클래스간의 조직을 표현할 필요가 없을 경우는 추상클래스를 쓰는 대신 인터페이스를 쓰는 경우가 많습니다. 인터페이스는 위에서 말씀드린바와 같이 모든 메소드가 추상메소드라서 이를 포함하는 클래스는 이들을 모두 구현해야 합니다.
 
추상메소드는 멤버변수(어트리뷰트)를 가지지만 인터페이스는 오직 '상수'만을 가질 수 있습니다.
 
* 추상메소드 상속과 오버라이딩
 
abstract class Employee{
String name,phone;
Employee(){}
Employee(String name,String phone){
this.name=name;
this.phone=phone;
}
public abstract String getInfo(); // abstract 추상 메소드(불구 메소드)
// 추상 클래스는 다른 클래스의 슈퍼 클래스 역활을 한다.
// 다른 클래스에 상속을 해줄 목적으로만 사용된다.
// 추상 클래스를 상속 받은 클래스에서는 상속받은 클래스를 반드시 오버라이딩해줘야 한다.
}

class C070521 extends Employee{
C070521(String name,String phone){
super(name,phone);
}
public static void main(String[] args){
Employee a = new C070521("김대경","그런거없다");
System.out.print(a.phone);
}
public String getInfo(){
return name+phone;
}
}
 
오버로딩이란?

메서드는 변수와 마찬가지로 같은 클래스 내에서 서로 구별될 수 있어야 하기 때문에 각기 다른 이름을 가져야 한다.
하지만, 자바에서는 한 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메서드가 있더라도 매개변수의 개수 또는 타입이 다르면, 같은 이름을 사용해서 메서드를 정의할 수 있도록 했다.

이처럼, 한 클래스 내에 같은 이름의 메서드를 여러 개 정의하는 것을 메서드 오버로딩(Method Overloading) 또는 간단히 오버로딩(Overloading)이라 한다.

오버로딩(Overloading)의 사전적 의미는 '과적하다.
' 즉, 많이 싣는 것을 뜻한다. 보통 하나의 메서드 이름에 하나의 기능만을 구현해야하는데, 하나의 메서드 이름으로 여러 기능을 구현하기 때문에 붙여진 이름이라 생각할 수 있다. 앞으로는 메서드 오버로딩을 간단히 오버로딩이라고 하겠다.

오버라이딩이란?

조상클래스로부터 상속받은 메서드의 내용을 변경하는 것을 오버라이딩이라고 한다. 상속받은 메서드를 그대로 사용하기도 하지만, 자손클래스 자신에 맞게 변경해야하는 경우가 많다. 이럴 때 조상의 메서드를 오버라이딩한다.

[참고]override의 사전적 의미는 '~위에 덮어쓰다(overwrite).'
                                         또는 '~에 우선하다.'이다.

오버로딩 vs. 오버라이딩

오버로딩과 오버라이딩은 서로 혼동하기 쉽지만 사실 그 차이는 명백하다.
오버로딩은 기존에 없는 새로운 메서드를 추가하는 것이고, 오버라이딩은 조상으로부터 상속받은 메서드의 내용을 변경하는 것이다.


오버로딩(Overloading) - 기존에 없는 새로운 메서드를 정의하는 것(new)
오버라이딩(Overriding) - 상속받은 메서드의 내용을 변경하는 것(change, modify)


아래의 코드를 보고 오버로딩과 오버라이딩을 구별할 수 있어야 한다.


class Parent {
     void parentMethod() {}
}

class Child extends Parent {
     void parentMethod() {} // 오버라이딩
     void parentMethod(int i) {} // 오버로딩

     void childMethod() {}
     void childMethod(int i) {} // 오버로딩
     void childMethod() {}       // 에러!!! 중복정의 되었음.(already defined in Child)
}

Posted by 행복한 프로그래머 궁금쟁이박
TAG Java

댓글을 달아 주세요

  1. BlogIcon munggeun 2014.01.07 22:39 신고  댓글주소  수정/삭제  댓글쓰기

    잘 정리된 글 감사합니다. ^^