태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

티스토리 툴바

※ System.currentTimeMills()와 System.nanoTime() 비교

 

● static long currentTimeMills(): 현재의 시간을 ms로 리턴한다.(1/1,000 초)
1970년 1월 1일 부터의 시간을 long 타입으로 리턴해 준다.

상용예)

long cur1 = System.currentTimeMills();
...
long elapsedTime = System.currentTimeMills() - cur1;
System.out.println(elapsedTime + "ms");


● static long nanoTime(): 현재의 시간을 ns로 리턴한다.(1/1,000,000,000 초)
JDK 5.0 부터 추가된 메소드이다. currentTimeMills()메소드는 1ms 이하의 시간을 측정하기가 어려움.
nanoTime()메소드는 수행된 시간 측정이 목적이기 때문에 오늘날짜 알아내는 부분에는 사용하면 안됨.

사용예)

long cur = System.nanoTime();
...
double elapsedTime(System.nanoTime() - cur) / 1000000.0;
System.out.println(elapsedTime + "ms");


♣ JDK 5.0 이상에서는 시간 측정용으로 만들어진 nanoTime() 메소드를 하용하기를 권장한다...

저작자 표시 비영리 동일 조건 변경 허락
크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2012/01/04 15:40
Java 에서는 두가지 방식으로 Thread를 생성할수 있다.

1. Thread Class 상속
2. Runnable Interface 구현

Thread와 Runnable 에 모두 선언되어 있는 void run() 메소드를 사용자는 오버라이드 하여 해당 작업을 기술하게 된다.

또한 run() method class의 start() method에 의해 호출되기 때문에 따로 호출 하지 않아도 된다.

Thread와 Runnable의 차이는 Class와 Interface에서도 볼 수 있다시피 "상속"의 차이다.

기본적으로 Java는 다중상속을 금지하고 있기 때문에 A라는 클래스가 B 클래스를 상속받아야 하며, A가 쓰레드로 동작되어야 할 경우, 

Runnable을 Implements하면 된다.

Runnable은 오로지 run() method만 정의되어 있으므로 thread에 대하여 다른 작업이 필요할 경우, 생성할 때 Thread t = new Thread(정의한 Runnable) 형태로 생성 사용해야 한다.

저작자 표시 비영리 동일 조건 변경 허락
크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2011/05/31 17:56

1> 패널 컨테이너란?

우선 Panel 클래스는 Applet 클래스의 상위 클래스이다.
Applet과 Frame은 가장 바깥쪽의 컨테이너 역활을 하는데 반해 Panel 컨테이너는 컴포넌트를 그룹별로 모을 때, 주로 사용한다. 보통 컴포넌트를 Panel 에 먼저 부착을 하고 Panel을 Applet 혹은 Frame 에 부착을 한다. 왜 이렇게 복잡하게 하느냐 싶겠지만, 실제로 Panel 은 불가피한 배치문제로 인해 많이 사용되고 있다. Panel 은 다른 컨테이너에 쉽게 부착을 할 수 있는데, 컴포넌트를 추가할 때와 마찬가지로 add() 메서드를 사용한다.

 

우선 예제를 보자. 나중에 살펴볼 배치를 배우게 되면 이해가 될 것이다.

2> 패널 컨테이너 사용 예

앞서 프레임 컨테이너에서 예를 든 LabelFrame.java에 패널을 사용했다.

1. LabelFramePanel.java

 


import java.awt.*;

public class LabelFramePanel extends Frame{

//일반적으로 프레임에서는 생성자에서 GUI를 구성한다.
public LabelFramePanel(){

// 라벨을 생성한다.
Label label1 = new Label("첫번째");
Label label2 = new Label("두번째");
Label label3 = new Label("세번째");

// 라벨에 배경색을 설정한다.
label1.setBackground(Color.red);
label2.setBackground(Color.yellow);
label3.setBackground(Color.green);

//패널 객체 생성
Panel p =new Panel();

//패널에 라벨을 차례대로 붙인다.
p.add(label1);
p.add(label2);
p.add(label3);

//패널을 프레임에 붙인다.
add(p);
}

public static void main(String[] args){

LabelFramePanel lf=new LabelFramePanel();
lf.setSize(300,100);
lf.show();

   }
}


<< 실행 결과 >>

이미지를 클릭하시면 원본크기로 보실수 있습니다.



출처 : getJAVA™

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/11/12 10:30

1> Frame 컨테이너

Frame 컨테이너는 어플리케이션의 대표적인 컨테이너이다. 이때까지 우리가 예제를 다룬것에서 그다지 벗어나지 않는다. Frame 컨테이너에서도 애플릿과 마찬가지로 add()를 이용해서 컴포넌트를 부착하면 된다. 다만 Frame 컨테이너는 부착을 할때 위치를 지정해 줘야한다. 또한 Frame 컨테이너의 크기를 결정해주는 setSize() 라든지 setBounds()를 반드시 코딩해 줘야하며 화면에 보이도록 setVisible(true)나 show() 메서드를 코딩해 줘야한다.

2> Frame 컨테이너 사용하기

  1. Frame 클래스 import 하기(import java.awt.Frame;)
  2. Frame 클래스 상속 받기
  3. setSize() 혹은 setBounds()로 크기 결정하기 --> 중요
  4. setVisible(true)나 show() 로 화면에 출력하기 --> 하지 않으면 화면에 보이지 않음.

3> Frame 컨테이너 사용 예

1. LabelFrame.java

 


// Frame 클래스를 import 한다.
// Frame 클래스는 awt 패키지에 속하므로 다음과 같이 해도 된다.
import java.awt.*;

public class LabelFrame extends Frame{

public static void main(String[] args){

//애플릿과는 달리 프레임은 객체를 생성해 줘야한다.
LabelFrame lf=new LabelFrame();

// 라벨을 생성한다.
Label label1 = new Label("첫번째");
Label label2 = new Label("두번째");
Label label3 = new Label("세번째");

// 라벨에 배경색을 설정한다.
label1.setBackground(Color.red);
label2.setBackground(Color.yellow);
label3.setBackground(Color.green);

// 라벨을 붙인다.
lf.add(label1);
lf.add(label2);
lf.add(label3);

// 반드시 크기결정과 화면출력을 해줘야한다.
// 에러는 나지 않지만 실행시 화면이 보이지 않는다.

lf.setSize(300,300);
lf.show();

    }
}


<< 실행 결과 >>

이미지를 클릭하시면 원본크기로 보실수 있습니다.



실행결과를 보면 좀 황당하다는 생각이 들것이다. 왜냐면 맨 마지막에 부착을 했던 라벨만이 보이기 때문이다. 이것은 애플릿과 프레임의 배치 관리자가 달라서 그렇다. 다시 말하면 애플릿은 붙이는 순서대로 붙는 배치가 디폴트이고 (이것을 FlowLayout 이라한다.) 프레임은 5가지로 영역이 나누어서 붙는 배치가 디폴트이기 때문이다.(이것을 BorderLayout 이라한다.)

 

아직 배치에 관해 배우지 않았으므로 결과에는 신경을 쓰지 말고 넘어가자.
어쨌든 여기서 중요한 것은 애플릿으로 코딩한 것을 프레임으로 혹은 프레임을 애플릿으로 바꾸는 연습을 많이하고 그 원리를 이해해야한다.


출처 : getJAVA™

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/11/12 10:27
7.1 인터페이스란?

인터페이스는 일종의 추상클래스이다. 인터페이스는 추상클래스처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높아서 추상클래스와 달리 몸통을 갖춘 일반 메서드 또는 멤버변수를 구성원으로 가질 수 없다.
오직 추상메서드와 상수만을 멤버로 가질 수 있으며, 그 외의 다른 어떠한 요소도 허용하지 않는다.
추상클래스를 부분적으로만 완성된 '미완성 설계도'라고 한다면, 인터페이스는 구현된 것은 아무 것도 없고 밑그림만 그려져 있는 '기본 설계도'라 할 수 있다.

추상클래스처럼 인터페이스도 완성되지 않은 불완전한 것이기 때문에 그 자체만으로 사용되기 보다는 다른 클래스를 작성하는데 도움 줄 목적으로 작성된다.



7.2 인터페이스의 작성

인터페이스를 작성하는 것은 클래스를 작성하는 것과 같다. 다만 키워드로 class 대신 interface를 사용한다는 것만 다르다. 그리고 interface에도 클래스와 같이 접근제어자로 public 또는 default를 사용할 수 있다.


interface 인터페이스이름 {
      public static final 타입 상수이름 = 값;
      public abstract 메서드이름(매개변수목록);
}


일반적인 클래스의 멤버들과 달리 인터페이스의 멤버들은 다음과 같은 제약사항을 가지고 있다.


- 모든 멤버변수는 public static final 이어야 하며, 이를 생략할 수 있다.
- 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다.

[참고]인터페이스에 정의된 모든 멤버에 예외없이 적용되는 사항이기 때문에 제어자를 생략할 수 있는 것이며, 편의상 생략하는 경우가 많다. 생략된 제어자는 컴파일시에 컴파일러가 자동적으로 추가해준다.



interface PlayingCard {
      public static final int SPADE = 4;
      final int DIAMOND = 3;             // public static final int DIAMOND=3;
      static int HEART = 2;             // public static final int HEART=2;
      int CLOVER = 1;                  // public static final int CLOVER=1;

      public abstract String getCardNumber();
      String getCardKind();       // public abstract String getCardKind();로 간주된다.
}





7.3 인터페이스의 상속

interface는 클래스가 아닌 인터페이스로부터만 상속받을 수 있으며, 클래스와는 달리 다중상속, 즉 여러 개의 인터페이스로부터 상속을 받는 것이 가능하다.

[참고]클래스와는 달리 Object클래스와 같은 모든 인터페이스의 최고조상은 없다.



interface Movable {
      /** 지정된 위치(x, y)로 이동하는 기능의 메서드 */
      void move(int x, int y);      
}

interface Attackable {
      /** 지정된 대상(u)을 공격하는 기능의 메서드 */
      void attack(Unit u);
}

interface Fightable extends Movable, Attackable { }


클래스에서의 상속과 마찬가지로 자손인터페이스(Fightable)은 조상인터페이스(Movable, Attackable)에 정의된 멤버를 모두 상속받는다.
그래서 Fightable자체에는 정의된 멤버가 하나도 없지만 조상인터페이스로 부터 상속받은 두 개의 추상메서드, move(int x, int y)와 attack(Unit u)를 멤버로 갖게 된다.




7.4 인터페이스의 구현

추상클래스에서와 같이 인터페이스의 추상메서드를 몸통을 구현하는 자손클래스를 작성해야한다. 이때는 인터페이스를 '구현(implement)한다'고 하며 키워드 implements를 사용한다.


class 클래스이름 implements 인터페이스이름 {
      // 인터페이스에 정의된 추상메서드를 구현해야한다.
}

class Fighter implements Fightable {
      public void move() { /* 내용 생략*/ }
      public void attack() { /* 내용 생략*/ }
}

[참고]이 때 'Fighter클래스는 Fightable인터페이스를 구현한다.'라고 한다.

만일 구현하는 인터페이스의 메서드 중 일부만 구현한다면, 추상클래스로 선언되어야 한다.


abstract class Fighter implements Fightable {
     public void move() { /* 내용 생략*/ }
}


그리고 다음과 같이 상속과 구현을 동시에 할 수도 있다.


class Fighter extends Unit implements Fightable {
      public void move(int x, int y) { /* 내용 생략 */}
      public void attack(Unit u) { /* 내용 생략 */}
}

[참고]인터페이스의 이름에는 주로 Fightable과 같이 '~ 를 할 수 있는'의 의미인 'able'로 끝나는 것들이 많은데, 그 이유는 어떠한 기능 또는 행위를 하는데 필요한 메서드를 제공한다는 의미를 강조하기 위해서이다. 또한 그 인터페이스를 구현한 클래스는 '~를 할 수 있는' 능력을 갖추었다는 의미이기도 하다.
이름이 'able'로 끝나는 것은 인터페이스라고 쉽게 추측할 수 있지만, 모든 인터페이스의 이름이 반드시 'able'로 끝나야 하는 것은 아니다.


[예제7-23] FighterTest.java

class FighterTest
{
      public static void main(String[] args)
      {
            Fighter f = new Fighter();

            if (f instanceof Unit)       {            
                  System.out.println("f는 Unit클래스의 자손입니다.");
            }
            if (f instanceof Fightable) {      
                  System.out.println("f는 Fightable인터페이스를 구현했습니다.");
            }
            if (f instanceof Movable) {            
                  System.out.println("f는 Movable인터페이스를 구현했습니다.");
            }
            if (f instanceof Attackable) {      
                  System.out.println("f는 Attackable인터페이스를 구현했습니다.");
            }
            if (f instanceof Object) {            
                  System.out.println("f는 Object클래스의 자손입니다.");
            }
      }
}

class Fighter extends Unit implements Fightable {
      public void move(int x, int y) { /* 내용 생략 */}
      public void attack(Unit u) { /* 내용 생략 */}
}

class Unit {
int currentHP;             // 유닛의 체력
int x;                   // 유닛의 위치(x좌표)
int y;                   // 유닛의 위치(y좌표)
}
interface Fightable extends Movable, Attackable { }
interface Movable {       void move(int x, int y);       }
interface Attackable {       void attack(Unit u); }

[실행결과]
f는 Unit클래스의 자손입니다.
f는 Fightable인터페이스를 구현했습니다.
f는 Movable인터페이스를 구현했습니다.
f는 Attackable인터페이스를 구현했습니다.
f는 Object클래스의 자손입니다.

예제에 사용된 클래스와 인터페이스간의 관계를 그려보면 다음과 같다.



실제로 Fighter클래스는 Unit클래스로부터 상속받고 Fightable인터페이스만을 구현했지만, Unit클래스는 Object클래스의 자손이고, Fightable인터페이스는 Movable과 Attackable인터페이스의 자손이므로 Fighter클래스는 이 모든 클래스와 인터페이스의 자손이 되는 셈이다.
인터페이스는 상속 대신 구현이라는 용어를 사용하지만, 인터페이스로부터 상속받은 추상메서드를 구현하는 것이기 때문에 인터페이스도 조금은 다른 의미의 조상이라고 할 수 있다.

여기서 주의 깊게 봐두어야 할 것은 Movable인터페이스에 정의된 void move(int x, int y)를 Fighter클래스에서 구현할 때 접근제어자를 public으로 했다는 것이다.


interface Movable {
      void move(int x, int y);      
}

class Fighter extends Unit implements Fightable {
      public void move(int x, int y) { /* 실제구현내용 생략 */}
      public void attack(Unit u) { /* 실제구현내용 생략 */}
}


오버라이딩을 할 때는 조상의 메서드보다 넓은 범위의 접근제어자를 지정해야한다는 것을 기억할 것이다. Movable인터페이스에 void move(int x, int y)와 같이 정의되어 있지만 사실 public abstract가 생략된 것이기 때문에 실제로 public abstract void move(int x, int y)이다.
따라서 이를 구현하는 Fighter클래스에서는 void move(int x, int y)의 접근제어자를 반드시 public으로 해야 하는 것이다.





7.5 인터페이스를 이용한 다중상속

두 조상으로부터 상속받는 멤버 중에서 멤버변수의 이름이 같거나 메서드의 선언부가 일치하고 구현 내용이 다르다면 이 두 조상으로부터 상속받는 자손클래스는 어느 조상의 것을 상속받게 되는 것인지 알 수 없다. 어느 한 쪽으로부터의 상속을 포기하던가, 이름이 충돌하지 않도록 조상클래스를 변경하는 수 밖에는 없다.

자바에서는 이러한 충돌문제를 해결하기 위해서 단일 상속만을 허용하고, 인터페이스를 이용해서 단일 상속의 단점을 보완하도록 하였다.

인터페이스는 상수만을 정의할 수 있으므로 조상클래스의 멤버변수와 충돌하는 경우는 극히 드물고 추상메서드는 구현내용이 전혀 없으므로 조상클래스의 메서드와 선언부가 일치하는 경우에는 당연히 조상클래스 쪽의 메서드를 상속받으면 되므로 문제되지 않는다.
이렇게 해서 상속받는 멤버의 충돌은 피할 수 있지만, 다중상속의 장점을 잃게 된다는 것이 아쉽다.

만일 두 개의 클래스로부터 상속을 받아야 할 상황이라면, 두 조상클래스 중에서 비중이 높은 쪽을 선택하고 다른 한쪽은 클래스 내부에 멤버로 포함시키는 방식으로 처리하거나 어느 한쪽을 필요한 부분을 뽑아서 인터페이스로 만든 다음 구현하도록 한다.

다음과 같이 Tv클래스와 VCR클래스가 있을 때, TVCR클래스를 작성하기 위해 두 클래스로부터 상속을 받을 수만 있으면 좋겠지만 다중상속을 허용하지 않으므로, 한 쪽만 선택하여 상속받고 나머지 한 쪽은 클래스 내에 포함시켜서 내부적으로 인스턴스를 생성해서 사용하도록 한다.


public class Tv {
      protected boolean power;
      protected int channel;
      protected int volume;
      public void power() { power = ! power;}
      public void channelUp() { channel++;}
      public void channelDown() { channel--;}
      public void volumeUp() { volume++;}
      public void volumeDown() { volume--;}
}

public class VCR {
      protected int counter;             // VCR의 카운터
      public void play() {
            // Tape을 재생한다.
      }
      public void stop() {
            // 재생을 멈춘다.
      }
     public void reset() {            
           counter =0;
     }
     public int getCounter() {
           return counter;
     }
     public void      setCounter(int c) {
           counter = c;
     }
}


VCR클래스에 정의된 메서드와 일치하는 추상메서드를 갖는 인터페이스를 작성한다.


public interface IVCR {
      public void play();
      public void stop();
      public void reset();
     public int getCounter();
     public void setCounter(int c);
}


이제 IVCR 인터페이스를 구현하고 Tv클래스로부터 상속받는 TVCR클래스를 작성한다. 이때 VCR클래스 타입의 참조변수를 멤버변수로 선언하여 IVCR인터페이스의 추상메서드를 구현하는데 사용한다.


public class TVCR extends Tv implements IVCR {
      VCR vcr = new VCR();      
      public void play() {
            vcr.play();   // 코드를 작성하는 대신 VCR인스턴스의 메서드를 호출하면 된다.
      }
      public void stop() {
            vcr.stop();
      }
      public void reset() {
           vcr.reset();
     }
     public int getCounter() {
          return vcr.getCounter();
     }
     public void setCounter(int c) {
          vcr.setCounter(c);
     }
}

IVCR인터페이스를 구현하기 위해서는 새로 메서드를 작성해야하는 부담이 있지만 이처럼 VCR클래스의 인스턴스를 사용하면 손쉽게 다중상속을 구현할 수 있다.
또한 VCR클래스의 내용이 변경되어도 변경된 내용이 TVCR클래스에도 자동적으로 반영되는 효과도 얻을 수 있다.

사실 인터페이스를 새로 작성하지 않고도 VCR클래스를 TVCR클래스에 포함시키는 것만으로도 충분하지만, 인터페이스를 이용하면 다형적 특성을 이용할 수 있다는 장점이 있다.




7.6 인터페이스를 이용한 다형성

다형성에 대해 학습할 때 자손클래스의 인스턴스를 조상타입의 참조변수로 참조하는 것이 가능하다는 것을 배웠다.
인터페이스 역시 이를 구현한 클래스의 조상이라 할 수 있으므로 해당 인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있으며, 인터페이스 타입으로의 형변환도 가능하다.
인터페이스 Fightable을 클래스 Fighter가 구현했을 때, 다음과 같이 Fighter인스턴스를 Fightable타입의 참조변수로 참조하는 것이 가능하다.


Fightable f = (Fightable)new Fighter();
또는
Fightable f = new Fighter();

[참고]물론 Fightable타입의 참조변수로는 인터페이스 Fightable에 정의된 멤버들만 호출이 가능하다.

따라서 인터페이스는 다음과 같이 메서드의 매개변수의 타입으로 사용될 수 있다.


void attack(Fightable f) {
     //...
}


인터페이스 타입의 매개변수가 갖는 의미는 메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공해야한다는 것이다.
그래서 attack메서드를 호출할 때는 매개변수로 Fightable인터페이스를 구현한 클래스의 인스턴스를 넘겨주어야 한다.


class Fighter extends Unit implements Fightable {
      public void move(int x, int y) { /* 내용 생략 */}
      public void attack(Fightable f) { /* 내용 생략 */}
}

위와 같이 Fightable인터페이스를 구현한 Fighter클래스가 있을 때, attack메서드의 매개변수로 Fighter인스턴스를 넘겨 줄 수 있다. 즉, attack(new Fighter())와 같이 할 수 있다는 것이다.

그리고 다음과 같이 메서드의 리턴타입으로 인터페이스의 타입을 지정하는 것 역시 가능하다.


Fightable method() {
     // ...
     return new Fighter();
}


리턴타입이 인터페이스라는 것은 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미한다.
위의 코드에서는 method()의 리턴타입이 Fightable인터페이스기 때문에 메서드의 return문에서Fightable인터페이스를 구현한 Fighter클래스의 인스턴스를 반환한다.


[예제7-24] ParserTest.java

class ParserTest {
      public static void main(String args[]) {
            Parseable parser = ParserManager.getParser("XML");
            parser.parse("document.xml");
            parser = ParserManager.getParser("HTML");
            parser.parse("document2.html");
      }
}

interface Parseable {
      public abstract void parse(String fileName);       // 구문 분석작업을 수행한다.
}

class ParserManager {
     // 리턴타입이 Parseable인터페이스이다.
      public static Parseable getParser(String type) {      
            if(type.equals("XML")) {
               return new XMLParser();
            } else {
               Parseable p = new HTMLParser();
               return p;
               // return new HTMLParser();       위의 두 줄을 간단히 할 수 있다.
            }
      }
}

class XMLParser implements Parseable {
      public void parse(String fileName) {
          /* 구문 분석작업을 수행하는 코드를 적는다. */
            System.out.println(fileName + " - XML parsing completed.");
      }
}

class HTMLParser implements Parseable {
      public void parse(String fileName) {
          /* 구문 분석작업을 수행하는 코드를 적는다. */
            System.out.println(fileName + " - HTML parsing completed.");
      }
}

[실행결과]
document.xml - XML parsing completed.
document2.html - HTML parsing completed.

Parseable인터페이스는 구문분석(parsing)을 수행하는 기능을 구현할 목적으로 추상메서드 parse(String fileName)를 정의했다. 그리고 XMLParser클래스와 HTMLParser클래스는 Parseable인터페이스를 구현하였다.
ParserManager클래스의 getParser메서드는 매개변수로 넘겨받는 type의 값에 따라 XMLParser인스턴스 또는 HTMLParser인스턴스를 반환한다.



getParser메서드의 수행결과로 참조변수 parser는 XMLParser인스턴스의 주소값을 갖게 된다. 마치 Parseable parser = new XMLParser();이 수행된 것과 같다.


parser.parse("document.xml");


참조변수 parser를 통해 parse()를 호출하면, parser가 참조하고 있는 XMLParser인스턴스의 parse메서드가 호출된다.

만일 나중에 새로운 종류의 XML구문분석기 NewXMLPaser클래스가 나와도 ParserTest클래스는 변경할 필요없이 ParserManager클래스의 getParser메서드에서 return new XMLParser(); 대신 return new NewXMLParser();로 변경하기만 하면 된다.

이러한 장점은 특히 분산환경 프로그래밍에서 그 위력을 발휘한다. 사용자 컴퓨터에 설치된 프로그램을 변경하지 않고, 서버측의 변경만으로도 사용자가 새로 개정된 프로그램을 사용하는 것이 가능하다.




7.7 인터페이스의 장점

인터페이스를 사용하는 이유와 그 장점을 정리해 보면 다음과 같다.


- 개발시간을 단축시킬 수 있다.
- 표준화가 가능하다.
- 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
- 독립적인 프로그래밍이 가능하다.


1. 개발시간을 단축시킬 수 있다.
일단 인터페이스가 작성되면, 이를 사용해서 프로그램을 작성하는 것이 가능하다. 메서드를 호출하는 쪽에서는 메서드의 내용에 관계없이 선언부만 알면 되기 때문이다.
그리고 동시에 다른 한 쪽에서는 인터페이스를 구현하는 클래스를 작성하도록 하여, 인터페이스를 구현하는 클래스가 작성될 때까지 기다리지 않고도 양쪽에서 동시에 개발을 진행할 수 있다.

2. 표준화가 가능하다.
프로젝트에 사용되는 기본 틀을 인터페이스로 작성한 다음 개발자들에게 인터페이스를 구현하여 프로그램을 작성하도록 함으로써 보다 일관되고 정형화된 프로그램의 개발이 가능하다.

3. 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
서로 상속관계에 있지도 않고, 같은 조상클래스를 가지고 있지 않은 서로 아무런 관계도 없는 클래스들에게 하나의 인터페이스를 공통적으로 구현하도록 함으로써 관계를 맺어 줄 수 있다.

4. 독립적인 프로그래밍이 가능하다.
인터페이스를 이용하면 클래스의 선언과 구현을 분리 시킬 수 있기 때문에 실제구현에 독립적인 프로그램을 작성하는 것이 가능하다. 클래스와 클래스간의 직접적인 관계를 인터페이스를 이용해서 간접적인 관계로 변경하면, 한 클래스의 변경이 관련된 다른 클래스에 영향을 미치지 않는 독립적인 프로그래밍이 가능하다.
예를 들어 한 데이터베이스 회사가 제공하는 특정 데이터베이스를 사용하는데 필요한 클래스를 사용해서 프로그램을 작성했다면 이 프로그램은 다른 종류의 데이터베이스를 사용하기 위해서는 전체 프로그램 중에서 데이터베이스 관련된 부분은 모두 변경해야할 것이다.

그러나 데이터베이스 관련 인터페이스를 정의하고 이를 이용해서 프로그램을 작성하면, 데이터베이스의 종류가 변경되더라도 프로그램을 변경하지 않도록 할 수 있다.

단, 데이터베이스 회사에서 제공하는 클래스도 인터페이스를 구현하도록 요구해야한다. 데이터베이스를 이용한 응용프로그램을 작성하는 쪽에서는 인터페이스를 이용해서 프로그램을 작성하고, 데이터베이스 회사에서는 인터페이스를 구현한 클래스를 작성해서 제공해야한다.

실제로 자바에는 다수의 데이터베이스 관련 인터페이스를 제공하고 있으며, 프로그래머는 이 인터페이스를 이용해서 프로그래밍을 하면 특정 데이터베이스에 종속되지 않는 프로그램을 작성할 수 있다.

게임 스타크래프드에 나오는 유닛을 클래스로 표현하고 이들간의 관계를 상속계층도로 표현해 보았다.



게임에 나오는 모든 유닛들의 최고 조상은 Unit클래스이고 유닛의 종류는 지상유닛(GoundUnit)과 공중유닛(AirUnit)으로 나뉘어진다.
그리고 지상유닛에는 Marine, SCV, Tank가 있고, 공중유닛으로는 DropShip이 있다. SCV에게 Tank와 DropShip과 같은 기계화 유닛을 수리할 수 있는 기능을 제공하기 위해 repair메서드를 정의한다면 다음과 같을 것이다.


void repair(Tank t) {
      // Tank를 수리한다.
}

void repair(DropShip d) {
      // DropShip을 수리한다.
}


이런 식으로 수리가 가능한 유닛의 개수 만큼 다른 버젼의 오버로딩된 메서드를 정의해야할 것이다.

이것을 피하기 위해 매개변수의 타입을 이 들의 공통 조상으로 하면 좋겠지만 DropShip은 공통조상이 다르기 때문에 공통조상의 타입으로 메서드를 정의한다고 해도 최소한 2개의 메서드가 필요할 것이다.



void repair(GroundUnit gu) {
      // 매개변수로 넘겨진 지상유닛(GroundUnit)을 수리한다.
}

void repair(AirUnit au) {
      // 매개변수로 넘겨진 공중유닛(AirUnit)을 수리한다.
}


그리고 GroundUnit의 자손 중에는 Marine과 같이 기계화 유닛이 아닌 클래스도 포함될 수 있기 때문에 repair메서드의 매개변수 타입으로 GroundUnit은 부적합하다.
현재의 상속관계에서는 이들의 공통점은 없다. 이 때 인터페이스를 이용하면 기존의 상속체계를 유지하면서 이들 기계화 유닛에 공통점을 부여할 수 있다.
다음과 같이 Repairable이라는 인터페이스를 정의하고 수리가 가능한 기계화 유닛에게 이 인터페이스를 구현하도록 하면 된다.


interface Repairable {}

class SCV extends GroundUnit implements Repairable {
      //...
}

class Tank extends GroundUnit implements Repairable {
      //...
}

class DropShip extends AitUnit implements Repairable {
      //...
}


이제 이 세 개의 클래스에는 같은 인터페이스를 구현했다는 공통저이 생겼다. 인터페이스 Repairable에 정의된 것은 아무것도 없고, 단지 인스턴스의 타입체크에 사용된다.
Repairable인터페이스를 중심으로 상속계층도를 그려보면 다음과 같다.



그리고, repair메서드의 매개변수의 타입을 Repairable로 선언하면, 이 메서드의 매개변수로 Repairable인터페이스를 구현한 클래스의 인스턴스만 받아들여질 것이다.


void repair(Repairable r) {
      // 매개변수로 넘겨받은 유닛을 수리한다.
}


앞으로 새로운 클래스가 추가될 때, SCV의 repair메서드에 의해서 수리가 가능하도록 하려면 Repairable인터페이스를 구현하도록 하면 될 것이다.

[예제7-25] RepairableTest.java

class RepairableTest
{
      public static void main(String[] args)
      {
            Tank t = new Tank();
            DropShip d = new DropShip();

            Marine m = new Marine();
            SCV       s = new SCV();

            s.repair(t);       // SCV가 Tank를 수리하도록 한다.
            s.repair(d);
//             s.repair(m);       에러발생 : repair(Repairable) in SCV cannot be applied to (Marine)
      }
}

interface Repairable {}
class GroundUnit extends Unit {
      GroundUnit(int hp) {
            super(hp);
      }
}

class AirUnit extends Unit {
      AirUnit(int hp) {
            super(hp);
      }
}

class Unit {
      int hitPoint;
      final int MAX_HP;
      Unit(int hp) {
            MAX_HP = hp;
      }
      //...
}

class Tank extends GroundUnit implements Repairable {
      Tank() {
            super(150);             // Tank의 HP는 150이다.
            hitPoint = MAX_HP;
      }

      public String toString() {
            return "Tank";
      }
      //...
}

class DropShip extends AirUnit implements Repairable {
      DropShip() {
            super(125);             // Goliath의 HP는 125이다.
            hitPoint = MAX_HP;
      }

      public String toString() {
            return "DropShip";
      }
      //...
}

class Marine extends GroundUnit {
      Marine() {
            super(40);
            hitPoint = MAX_HP;
      }
      //...
}


class SCV extends GroundUnit implements Repairable{
      SCV() {
            super(60);
            hitPoint = MAX_HP;
      }

      void repair(Repairable r) {
            if (r instanceof Unit) {
                  Unit u = (Unit)r;
                  while(u.hitPoint==u.MAX_HP) {
                        /* Unit의 HP를 증가시킨다. */
                        u.hitPoint++;
                  }
                  System.out.println( u.toString() + "의 수리가 끝났습니다.");
            }
      }      
      //...
}

[실행결과]
Tank의 수리가 끝났습니다.
DropShip의 수리가 끝났습니다.

repair메서드의 매개변수 r은 Repairable타입이기 때문에 인터페이스 Repairable에 정의된 멤버만 사용할 수 있다.
그러나 Repairable에는 정의된 멤버가 없으므로 이 타입의 참조변수로는 할 수 있는 일은 아무 것도 없다.
그래서 instanceof연산자로 타입을 체크한 뒤 캐스팅하여 Unit클래스에 정의된 hitPoint와 MAX_HP를 사용할 수 있도록 하였다.
그 다음엔 유닛의 현재체력(hitPoint)이 유닛이 가질 수 있는 최고체력(MAX_HP)이 될 때 Marine은 Repairable인터페이스를 구현하지 않았으므로 SCV클래스의 repair메서드의 매개변수로 Marine을 사용하면 컴파일 시에 에러가 발생한다.

이와 유사한 예를 한가지 더 들어보자. 게임 스타크래프트에 나오는 건물들을 클래스로 표현하고 이들의 관계를 상속계층도로 표현하였다.



건물을 표현하는 클래스 Academy, Bunker, Barrack, Factory가 있고 이들의 조상인 Building클래스가 있다고 하자. 이 때 Barrack클래스와 Factory클래스에 다음과 같은 내용의, 건물을 이동시킬수 있는, 새로운 메서드를 추가하고자 한다면 어떻게 해야할까?


void liftOff() { /* 내용생략 */}
void move(int x, int y) { /* 내용생략 */}
void stop() { /* 내용생략 */}
void land() { /* 내용생략 */}


Barrack클래스와 Factory클래스 모두 위의 코드를 적어주면 되긴 하지만, 코드가 중복된다는 단점이 있다. 그렇다고 해서 조상클래스인 Building클래스에 코드를 추가해주면, Building클래스의 다른 자손인 Academy와 Bunker클래스도 추가된 코드를 상속받으므로 안된다.
이런 경우에도 인터페이스를 이용해서 해결할 수가 있다. 우선 새로 추가하고자하는 메서드를 정의하는 인터페이스를 정의하고 이를 구현하는 클래스를 작성한다.


interface Liftable {
     /** 건물을 들어 올린다. */
     void liftOff();
     /** 건물을 이동한다. */
     void move(int x, int y);
     /** 건물을 정지시킨다. */
     void stop();
     /** 건물을 착륙시킨다. */
     void land();
}

class LiftableImpl implements Liftable {
     void liftOff() { /* 내용 생략 */}
     void move(int x, int y) { /* 내용 생략 */ }
     void stop() { /* 내용 생략 */ }
     void land() { /* 내용 생략 */ }
}


마지막으로 새로 작성된 인터페이스와 이를 구현한 클래스를 Barrack과 Factory클래스에 적용하면 된다.


class Barrack extends Buildings implments Liftable {
     LiftableImpl l = new LiftableImpl();
     void liftOff() { l.liftOff();}
     void move(int x, int y) { l.move(x, y);}
     void stop() { l.stop();}
     void land() { l.land();}
     void trainMarine() { /* 내용 생략 */ }
     void trainMedic() { /* 내용 생략 */ }
          // ...
}

class Factory extends Buildings implments Liftable {
     LiftableImpl l = new LiftableImpl();
     void liftOff() { l.liftOff();}
     void move(int x, int y) { l.move(x, y);}
     void land() { l.land();}
     void trainMarine() { /* 내용 생략 */ }
     void trainMedic() { /* 내용 생략 */ }
     // ...
}

Barrack클래스가 Liftable인터페이스를 구현하도록 하고, 인터페이스를 구현한 LiftableImpl클래스를 Barrack클래스에 포함시켜서 내부적으로 호출해서 사용하도록 한다.
이렇게 함으로써 같은 내용의 코드를 Barrack클래스와 Factory클래스에서 각각 작성하지 않고 LiftableImpl클래스 한 곳에서 관리할 수 있다. 그리고 작성된 Liftable인터페이스와 이를 구현한 LiftableImpl클래스는 후에 다시 재사용될 수 있을 것이다.







7.8 인터페이스의 이해


지금까지 인터페이스의 특징과 구현하는 방법, 장점 등 인터페이스에 대한 일반적인 사항들에 대해서 모두 살펴보았다. 하지만 '인터페이스란 도대체 무엇인가?'라는 의문은 여전히 남아있을 것이다. 이번 절에서는 인터페이스의 규칙이나 활용이 아닌, 본질적인 측면에 대해 살펴보자.

먼저 인터페이스를 이해하기 위해서는 다음의 두가지 사항을 반드시 염두에 두고 있어야 한다.


- 클래스를 사용하는 쪽(User)과 클래스를 제공하는 쪽(Provider)이 있다.
- 메서드를 사용(호출)하는 쪽(User)에서는 사용하려는 메서드(Provider)의
선언부만 알면 된다.(내용은 몰라도 된다.)


다음과 같이 클래스 A와 클래스 B가 있다고 하자.


class A {
      public static void main(String args[]) {
            B b = new B();
            b.methodB();
      }
}

class B {
      public void methodB() {
            System.out.println("methodB()");
      }
}


클래스 A(User)는 클래스 B(Provider)의 인스턴스를 생성하고 메서드를 호출한다. 이것을 간단히 'A-B'라고 표현하자. 이 두 클래스는 서로 직접적인 관계에 있다.


이 경우 클래스 A를 작성하기 위해서는 클래스 B가 이미 작성되어 있어야 한다. 그리고 클래스 B의 methodB()의 선언부가 변경되면, 이를 사용하는 클래스 A도 변경되어야 한다.
이와 같이 직접적인 관계의 두 클래스는 한 쪽(Provider)가 변경되면 다른 한 쪽(User)도 변경되어야 한다는 단점이 있다.

그러나 클래스 A가 클래스 B를 직접 호출하지 않고 인터페이스를 매개체로 해서 클래스 A가 인터페이스를 통해서 클래스 B의 메서드에 접근하도록 하면, 클래스 B에 변경사항이 생기거나 클래스 B와 같은 기능의 다른 클래스로 대체 되어도 클래스 A는 전혀 영향을 받지 않도록 하는 것이 가능하다.

두 클래스간의 관계를 간접적으로 변경하기 위해서는 먼저 인터페이스를 이용해서 클래스 B(Provider)의 선언과 구현을 분리해야한다.

먼저 다음과 같이 클래스 B에 정의된 메서드를 추상메서드로 정의하는 인터페이스 I를 정의한다.


interface I {
     public abstract void methodB();
}


그 다음에는 클래스 B가 인터페이스 I를 구현하도록 한다.


class B implements I {
     public void methodB() {
           System.out.println("methodB in B class");
      }
}


이제 클래스 A는 클래스 B 대신 인터페이스 I를 사용해서 작성할 수 있다.


class A {
      public void methodA(I i) {
            i.methodB();
      }
}

[참고]methodA가 호출될 때 인터페이스 I를 구현한 클래스의 인스턴스(클래스 B의 인스턴스)를 제공받아야 한다.

클래스 A를 작성하는데 있어서 클래스 B가 사용되지 않았다는 점에 주목하자. 이제 클래스 A와 클래스 B는 'A-B'의 직접적인 관계에서 'A-I-B'의 간접적인 관계로 바뀐 것이다.



결국 클래스 A는 여전히 클래스 B의 메서드를 호출하지만, 클래스 A는 인터페이스 I하고만 직접적인 관계에 있기 때문에 클래스 B의 변경에 영향을 받지 않도록 하는 것이 가능하다.
클래스 A는 인터페이스를 통해 실제로 사용하는 클래스의 이름을 몰라도 되고 심지어는 실제로 구현된 클래스가 존재하지 않아도 문제되지 않는다.

클래스 A는 직접적인 관계에 있는 인터페이스 I의 영향만을 받는다.



인터페이스 I는 실제구현 내용(클래스 B)을 감싸고 있는 껍데기이며, 클래스 A는 껍데기 안에 어떤 알맹이(클래스)가 들어 있는지 몰라도 된다.

[예제7-26] InterfaceTest.java

class A {
      void autoPlay(I i) {
            i.play();
     }
}

interface I {
      public abstract void play();
}

class B implements I {
     public void play() {
            System.out.println("play in B class");
      }
}

class C implements I {
     public void play() {
            System.out.println("play in C class");
      }
}

class InterfaceTest {
      public static void main(String[] args) {
            A a = new A();
            a.autoPlay(new B());
            a.autoPlay(new C());
      }
}

[실행결과]
play in B class
play in C class

[참고]클래스 A를 작성하는데 클래스 B가 관련되지 않았다는 사실에 주목한다.

클래스 A가 인터페이스 I를 사용해서 작성되긴 하였지만, 이처럼 매개변수를 통해서 인터페이스 I를 구현한 클래스의 인스턴스를 동적으로 제공받아야 한다.
클래스 Thread의 생성자인 Thread(Runnable target)와 AWT컴포넌트의 addActionListener(ActionListener l)가 이런 방식으로 되어 있다.

[참고]Runnable과 ActionListener는 인터페이스이다.

이처럼 매개변수를 통해 동적으로 제공받을 수 도 있지만 다음과 같이 다른 제 3의 클래스를 통해서 제공받을 수도 있다. JDBC의 DriverManager클래스가 이런 방식으로 되어 있다.

[예제7-27] InterfaceTest2.java

class InterfaceTest2 {
      public static void main(String[] args) {
            A a = new A();
            a.methodA();
      }
}

class A {
      void methodA() {
           I i = InstanceManager.getInstance();
            i.methodB();
      }
}

interface I {
      public abstract void methodB();
}

class B implements I {
      public void methodB() {
           System.out.println("methodB in B class");
      }
}

class InstanceManager {
      public static I getInstance() {
            return new B();
      }
}

[실행결과]
methodB in B class

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/11/08 11:12
문자열 다루기 - 분리 split함수

Split함수는 문자열을 기준문자로 분리할 수 있는 함수로 분리결과는 배열로 리턴된다

관리자모드를 간단하게 꾸밀 때 사용할 수 있다.

에제는 FSO(파일시스템객체)를 다룰 때 살펴본다

관리자로그인폼 -> 아이디와 패스 전송 -> 텍스트파일을 읽어 분리. 아이디와 패스 비교
-> 관리자전용화면.수정.수정값 전송 -> 전송결과를 기준문자를 넣어 다시 텍스트파일에 저장


split.asp
아이디 : guest 패 스 : 1234

소스

<%
str1="2-300-#ff6666-guest-1234"
spl=split(str1,"-") '대상문자열,분리기준 ->배열이 된다
%>

<table border="<%=spl(0)%>" width="<%=spl(1)%>" bgcolor="<%=spl(2)%>">
<tr>
<td> 아이디 : <%=spl(3)%> </td>
<td> 패 스: <%=spl(4)%> </td>
</tr>
</table>




public class Test {
    public static void main(String[] args) {
        String temp = "123.456"; //temp에 쪼갤 문자 넣기
        String[] temp2 = new String[2]; //배열 선언
        temp2 = temp.split("[.]"); //쪼개 넣기
        System.out.println(temp2[0]); //쪼개 넣은거 출력
    }
}


출력결과 = 123

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/11/08 02:59

◎ File 객체가 참조하는 파일, 디렉토리를 테스트하기 위한 메서드



canRead() - File 객체가 참조하는 파일 또는 디렉토리를 읽을 권

한이 있다면 true를, 없다면 false를 리턴한다. 만약 권한이 없는데

읽으려고 시도하면 SecurityException이 발생한다.

canWriter() - File 객체가 참조하는 파일 또는 디렉토리에 쓰

기 권한이 있다면 true를, 없다면 false를 리턴한다. 만약 권한

이 없는데 읽으려고 시도하면 SecurityException이 발생한다.



크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/11/08 02:45


텍스트 파일 저장시 개행문자 넣고 그 파일을 다운로드하여 메모장으로 오픈했을때,

로우가 아래로 내려가지 않고 ■ 으로 표시되고 한줄로만 보이게 된다.

(엑셀이나 다른 워드프로그램으로 보면 제대로 보인다.)

메모장에서도 한줄 한줄 정돈된 모습으로 보고자 한다면

\r\n으로 라인을 구분하여 넣어주면 모습이 제대로 잡히게 된다.

아니면 문장에 \r을 넣고 newLine(); 메소를 사용해도 된다.





크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/11/08 02:37
출처 카페 > 용마 겅부방 / 용마
원본 http://cafe.naver.com/yongmacafe/125

출처 : http://cafe.naver.com/javalicense.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=123


번 호 1  
ERROR Exception in thread "main" java.lang.NoClassDefFoundError: 파일명
발생되는 경우 클래스 파일을 찾을 수 없는 경우
조 언 실행하려는 클래스 파일 이름이 제대로 되어 있는지 확인한다.
또한, CLASSPATH 설정이 제대로 되어 있는지 확인하며 (도스모드에서 set명령어)
만약, 되어있지 않다면 설정한다. (CLASSPATH = jdk1.3/jre/lib/rt.jar; 2-1강좌 참조)
 
번 호 2  
ERROR cannot resolve symbol
symbol : class in(에러가 난 부분)
location : class StackTest(찾으려는 위치)
발생되는 경우 이해할 수 없는 클래스나 메소드, 변수명이 올경우
조 언 보통 이 에러는 철자가 틀렸을 경우에 많이 발생한다. 클래스, 메소드, 변수의 철자를 세심히 확인해 본다.
특히, 철자를 확인할때 대소문자 구분을 확실히 체크한다.(자바는 대소문자를 구별한다.) 그리고 클래스에서 발생할 경우 import를 해주었는지 확인해 봅니다.
 
번 호 3  
ERROR non-static variable 변수이름(or method 메소드이름) cannot br referenced from a static context
발생되는 경우 static 메소드 안에서 static 으로 선언되지 않은 메소드나 변수를 참조(사용)했을 경우.
특히, 메소드의 경우는 인스턴스를 사용하지 않고 static메소드 내에서 바로 선언한 경우.
조 언 static 선언자의 사용여부를 살펴보고 static 메소드 안에 static으로 선언되어지지 않은 메소드나 변수가 있느지 확인해본다.
만약 그런것이 있으면 메소드를 새로 만들어 그쪽에서 선언한다. 단, 인스턴스를 생성해서 불러줘야 한다는 것을 잊지 말아야한다.
 
번 호 4  
ERROR valiable 변수명 might not have been initialized
발생되는 경우 지역변수인 변수명의 변수가 초기화가 되어있지 않았을 경우
조 언 지역변수(메소드 내에서 선언한 변수)를 초기화 하지 않은채 선언했을 경우 발생한다.
멤버 필드가 아닌 경우는 반드시 변수 선언시 초기화를 해주어야 한다.
(멤버 필드는 자바 프로그램 자체에서 자동으로 default값으로 초기화 해준다.)
 
번 호 5  
ERROR class 클래스명 is public, should be declared in a file named 클래스명.java
발생되는 경우 클래스명이 public으로 선언되었는데 파일명과 다를 경우
조 언 public으로 선언된 클래스가 있다면 반드시 그 클래스명과 파일명이 같아야 한다.
클래스명과 파일명의 대소문자 및 철자가 같은지 비교해 본다.
또한, public으로 선언된 클래스가 하나 이상 있는지 찾아본다.(반드시 하나만 있어야한다.)
 
번 호 6  
ERROR push(java.lang.object)[메소드(인자로 받을 수 있는 형)] in java.util.Stack(메소드의 클래스) cannot be applied to (int)[잘못 들어간 형]
발생되는 경우 메소드에서 인자를 받을 때 받을 수 있는 형이 아닌 자료형 또는 클래스형을 사용할 경우
조 언 사용하는 메소드의 API를 참고하여 어떤 형을 인자로 받을 수 있는지 찾아본다.
API를 보지 못할 경우는 각 자료형으로 인자를 직접 바꾸어 본다.
 
번 호 7  
ERROR java.lang.NoSuchMethodError: main
Exception in thread "main"
발생되는 경우 클래스 파일 안에서 main() 메소드를 찾을 수 없는 경우
조 언 자바 애플릿이 아닌 이상 자바 애플리케이션은 반드시 main() 메소드를 사용해야 합니다.
main() 메소드를 빼먹지 않았는지 확인해 보십시요. 또한 public static void main(String[] args) 형식으로 씌어졌는지도 확인해 보십시요.
(main 클래스는 반드시 위와 같은 형식으로 만들어져야 합니다.)
 
번 호 8  
ERROR unreported exception java.io.IOException(Exception명); must be caught or declared to be thrown
발생되는 경우 예외가 발생하는데 예외처리를 해주지 않았을 경우
조 언 예외를 발생하는 메소드 같은 경우는 반드시 예외처리를 해주어야 합니다.
예외를 발생하거나 예외처리를 해야하는 메소드는 API를 확인해 보시면 알 수 있습니다.
그렇지 않다면 컴파일 후 지금처럼 에러가 난 예외를 예외처리해 주시면 됩니다.
또한, 예외를 처리할 때는 메소드 차원에서 throws 예외명을 이용해서 처리할 수 있고
try{} catch{} 구문을 이용해서 직접 처리해 주셔도 됩니다.(예외 강좌를 참고하세요.)
특히, 예외도 클래스이므로 반드시 예외가 들어간 패키지를 import 해주어야 합니다.
 
번 호 9  
ERROR Note : Calculator.java(파일명) uses or overrides a deprecated API.
Note : Recompile with -deprecation for details.
발생되는 경우 JDK 버전이 높아졌거나 보안등의 기타이유로 사용이 deprecated된 메소드를 사용한 경우
조 언 이건 예외라기 보다는 경고 입니다.(실행하면 됩니다.^^)
JDK가 버전이 높아지거나 보안등의 이유에 따라 예전에 만들어졌지만 필요가 없어지거나 대체된 메소드가 생겨났습니다.
그런 메소드를 deprecated 되었다고 하는데 이것은 API상에 나왔있습니다.
또한, 컴파일할때 -deprecation 옵션주면 어떤 메소드가 deprecate됐는지 알수있읍니다.
사용이 중지 됐다고 보기 보다는 사용을 가능하면 하지 않게끔 해주는 거죠.
대치되었거나 버전 업된 메소드를 사용하시면 됩니다.
 
번 호 10  
ERROR MouseEvent(클래스명) should be declared abstract; it does not define mouseDragged(java.awt.event.MouseEvent)[메소드명(메소드가 포함된 클래스)] in MouseEvent(클래스명)
발생되는 경우 implements한 Interface의 모든 메소드를 구현하지 않아서 발생됨
조 언 Interface는 모든 메소드가 선언만 되고 구현되지 않은 추상(abstract) 메소드입니다.
만약 Interface를 implements하려면 implements한 클래스가 Interface에서 선언한 모든 메소드를 구현해 주어야 합니다.
하나라도 빠질 경우 implements한 클래스도 추상 클래스로 보고 에러가 발생합니다.
에러에 구현해 주어야할 메소드명이 나오므로 그곳에 쓰여있는 메소드를 구현해 주면 됩니다.
만약, 그 메소드를 구현해 주었는데 에러가 나면 철자 및 대소문자를 다시 확인해 보십시요.
 
번 호 11  
ERROR incompatible types
found : /null(입력한 자료형)
required : int(요구하는 자료형)
발생되는 경우 입력을 했을때 맞지 않는 자료형이나 클래스형을 입력할 경우
조 언 incompatible 은 '성미가 맞지 않는','모순된' 이라는 뜻을 가진 단어 입니다.
단어뜻 처럼 입력 경우 required 에 나타난 자료형 및 클래스형을 요구하는데
found 에서 나타난 자료형 및 클래스형을 써주어서 입력을 하지 못하게 되어서 발생하는 에러입니다.
found 에 나타난 자료형을 required 에 나타난 자료형으로 변경해 주시면 됩니다.
 
번 호 12  
ERROR package java.servlet(패키지명) does not exist
발생되는 경우 import한 패키지가 존재하지 않을 경우
조 언 import한 패키지가 존재하지 않을 경우에 발생하는 에러입니다.
철자와 대소문자를 먼저 확인하고 CLASSPATH 설정을 확인해 보시기 바랍니다.
또한 그 곳에 패키지가 jar파일로 있는지도 확인해 보셔야 합니다.
(API에 나와있는 패키지는 rt.jar에 다 있습니다.
단 javax가 붙거나 다름으로 시작되는 확장 패키지는 설치해 주어야합니다.(javax.swing 제외))
 
번 호 13  
ERROR java.lang.NullPointerException
Exception in thread "main"(메소드) java.lang.NullPointerException
at java.awt.Container.addImpl(Container.java:341)... [에러가 일어난 부분]
발생되는 경우 참조하거나 사용한 클래스 또는 자료형이 초기화 되지 않은 경우
조 언 보통 이것은 awt나 배열 부분에서 자주 발생하는데 초기화를 해주지 않아서 많이 발생합니다.
자바의 변수들은 기본적으로(자동으로 초기화 되는 멤버필드등을 제외하고) 초기화를 요구합니다.
에러에 체크된 부분을 검토해 보시고 초기화를 해주십시요.
 
번 호 14  
ERROR ';'(빠진 부분) expected
발생되는 경우 문법상으로 써야할 것을 쓰지 않은 경우 발생합니다.
조 언 주로 ';'을 안써주시거나 아님 '()'(괄호)를 열기만 하고 닫지 않은 실수를 할 경우 발생합니다.
대부분 이 에러가 발생한 경우는 에러에 나온것을 소스에 추가해 주시면 됩니다.
 
번 호 15  
ERROR unexpected type
required : value(요구하는 타입)
found : class(소스상 써준 타입)
발생되는 경우 써주어야 할 타입이 아닌 잘못된 타입을 써주었을 경우
조 언 unexpected type 에러를 해석하면 '기대하지 않은 타입'이란 뜻을 가지고 있습니다.
즉, 원하는 타입(required)이 아닌데 잘못된 타입(found)을 써준 경우 발생합니다.
에러 체크된 부분의 타입을 required 에서 나타난 타입으로 변경해 주시면 됩니다.
 
번 호 16  
ERROR java.lang.ArrayIndexOutOfBoundsException
at Test.main(Test.java:10)[클래스.메소드(파일명:에러난 위치)]
Exception in thread "main"(예외가 던져진 메소드)
발생되는 경우 배열의 범위를 넘어선 값을 넣었을 경우
조 언 위의 에러는 특이하게 컴파일은 이상없이 되지만 실행을 하면 발생하는 에러입니다.
배열의 범위를 넘어설 경우에 발생하므로 에러난 위치의 배열의 참조 범위를 확인해보시고
선언해둔 배열의 범위에 맞게 조정해 주시면 됩니다.
 
번 호 17  
ERROR illegal start of expression
발생되는 경우 선언자(modifier)를 잘못 집어 넣은 경우
조 언 에러의 단어뜻을 확인해 보면 '표현의 시작이 부적격 합니다.'하고 해석할 수 있습니다.
보통 선언자가 맞지 않거나 쓰일데가 아닌데 선언자를 줄 경우에 많이 발생합니다.
특히 메소드안에서 static 선언자를 쓴 경우에는 직격으로 볼수 있죠.
에러가 난 부분의 선언자를 제거하거나 맞는 것인지 다시 확인해 보십시요.
 
번 호 18  
ERROR java.io.InputStream(클래스) is abstract; cannot be instantiated
발생되는 경우 abstract로 선언된 클래스를 직접 new 명령어를 이용하여 인스턴스화 할 경우
조 언 abstract로 선언된 클래스를 직접 new 명령어를 이용하여 인스턴스화 할 경우에 발생하는 에러입니다.
왜냐하면, 추상 클래스는 직접 new 명령어를 이용하여 인스턴스화 할수 없기 때문입니다.(객체를 못만든다구요.)
이 경우에는 인스턴스를 다른 방법으로 생성하시면 됩니다.
예를 들어 인스턴스를 반환하는 메소드를 이용한다거나 상속을 통해서 상속받은 클래스의 인스턴스를 만들어
직접 인스턴스를 만드는 효과를 낼수도 있구요. 원하시는 방법으로 바꾸어 보시길...
 
번 호 19  
ERROR local variable name(변수명) is accessed from within inner class; needs to be declared final
발생되는 경우 Local Class의 변수를 final로 선언하지 않은 경우
조 언 Local Class의 변수는 참조변수의 참조값 변동을 방지하기 위하여 final 선언자를 붙여주어야 합니다.
변수에 final 선언자를 붙이면 변수는 값을 변동할 수 없는 상수 처럼 쓰이며
만약 이 값을 참조할 경우 자바는 이 값을 넘기는게 아니라 이 값의 복사본을 참조 값으로 넘기게 됩니다.
그러므로 Local Class에서 참조값 변동없이 변수를 참조할 수 있게 되는 것입니다.
Local Class를 정의해준 곳을 살펴보고 final 선언자를 확실하게 확인하시기 바랍니다.
 
번 호 20  
ERROR inner classes cannot have static declarations
발생되는 경우 내부 클래스 안에서 static 선언자를 쓴 경우
조 언 내부 클래스 안에서는 static 선언자를 쓸수 없습니다.
내부 클래스 안에서 사용된 static 선언자를 제거해 주십시요.
 
번 호 21  
ERROR referenceto List is ambiguous,both class java.util.List(클래스) in java.util(패키지)
and class java.awt.List(클래스) in java.awt(패키지) match
발생되는 경우 클래스 사용시 다른 패키지내에 동일이름의 클래스들이 있어서 참조가 모호할 경우
조 언 예시를 보면 아시겠지만 import 한 패키지중에 같은 이름을 사용하는 클래스를 클래스 이름만으로
생성함으로서 참조가 모호해질 경우 발생하는 에러입니다.
이와 같은 경우는 import를 하나 제거 하거나 아님 java.util.List 이런식으로
직접 그 클래스의 패키지를 같이 써줌으로서 모호성을 제거할수 있습니다.
 
번 호 22  
ERROR m()(메소드명) in B(클래스명) cannot override m()(메소드명) in A(클래스명);
attempting to use incompatiable return type
발생되는 경우 클래스를 상속받고서 메소드를 오버라이드 하고자할때 잘못한 경우
조 언 클래스를 상속받고서 메소드를 오버라이드 할 경우에는 지켜야 하는 규칙이 있습니다.
1. 메소드의 이름이 같아야 합니다.
2. 메소드의 파라미터 개수, 데이터형이 같아야 합니다.
3. 메소드의 리턴형이 같아야 합니다.
4. 상위 메소드와 동일하거나 더 구체적인 Exception을 발생시켜야 합니다.
5. 상위 메소드와 동일하거나 접근범위가 더 넣은 접근 제한자를 사용해야 합니다.

님의 메소드 오버라이드시 위 규칙을 잘 지켰는가를 다시 한번 확인해 보세요.
 
번 호 23  
ERROR getPathBetweenRows(int,int)(메소드) has protected access in javax.swing.jTree(클래스)
발생되는 경우 protected로 선언된 메소드를 상속 없이 직접 불러쓸 경우
조 언 protected로 선언되어 있는 메소드는 상속하거나 같은 package에 있을 때만 쓸 수 있습니다.
상속해서 다시 public 메소드로 값을 받던지 아니면
public 메소드 중에서 비슷한 기능을 하는 메소드가 있는지 찾아서 바꾸어주어야 합니다.
 
번 호 24  
ERROR invalid method declaration; return type required
발생되는 경우 리턴 타입을 쓰지 않아 메소드의 선언이 잘못된 경우
조 언 리턴 타입을 쓰지 않아 메소드의 선언이 잘못된 경우에 발생하는 에러이므로
에러가 발생한 메소드를 확인해보고 리턴 타입을 맞게 적어주어야 합니다.
 
번 호 25  
ERROR Error occurred during initialization of VM
java.lang.ExceptionInInitializerError
발생되는 경우 static으로 선언된 변수중 초기화가 안되어 있는 것이 있는 경우
조 언 static으로 선언된 변수중에 초기화가 안된게 있는 경우에 발생하는 에러이므로
에러가 발생한 변수를 확인해보고 알맞은 초기화를 시켜주거나 변수의 위치를
자동 초기화가 가능한 메소드 밖의 클래스 변수로서 사용하게 합니다.
 
번 호 26  
ERROR Error opening registry key 'Software\JavaSoft\Java Runtime Environment'
Error: could not find java.dll
Error: could not find Java 2 Runtime Environment
발생되는 경우 중복설치 등으로 인해 레지스트리 키값이 잘못되어 있는 경우
조 언 중복설치 등으로 인해 레지스트리 키값이 잘못되어 있는 경우에 발생하는 에러이므로
레지스트리 편집기를 열어서 HKEY_LOCAL_MACHINE -> SOFTWARE -> JavaSoft에
보시면 3개의 키가 있을 겁니다. 그중에서 첫번째 키인 Java 런타임 환경 을 마우스
오른쪽 버튼으로 클릭하여 Java Runtime Environment로 이름을 바꿔주시면 됩니다.
 
번 호 27  
ERROR Error Registry Key 'Sofrware\JavaSofrware\Java Runtime Environment\CurrentVerison'
has value '1.1',but '1.3' is requried.
Error: could not find java.dll
Error: could not find java 2 Runtime Enviroment.
발생되는 경우 중복설치 등으로 인해 레지스트리 키값의 자바 버전이 잘못되어 있는 경우
조 언 중복설치 등으로 인해 레지스트리 키값의 자바 버전이 잘못되어 있는 경우에 발생하는 에러이므로
레지스트리 편집기를 열어서 HKEY_LOCAL_MACHINE -> SOFTWARE -> JavaSoft -> Java Runtime Environment의 Current version의 값을 1.3으로 되어있는지 확인해 주시면 됩니다.
 
번 호 28  
ERROR java.lang.ClassNotFoundException: org.gjt.mm.mysql.Driver(드라이버명)
발생되는 경우 JDBC로 데이터 베이스에 연결하는 중 드라이버를 찾지 못할 경우
조 언 JDBC를 연결하는 중에 드라이버를 찾지 못할 경우에 발생하는 에러이므로
각 데이터 베이스에 맞는 드라이버가 제대로 다운로드 되었는지 확인해 보시고
드라이버의 위치가 클래스 패스에 잡혀 있는지 확인해주시면 됩니다.
 
번 호 29  
ERROR Method printIn(java.lang.String)(메소드명) not found in class java.io.PrintStream(클래스명)
발생되는 경우 자신이 사용한 클래스의 메소드가 맞지 않는(=없는)경우
조 언 자신이 사용한 클래스의 메소드가 맞지 않는(=없는) 경우에 발생하는 에러이므로
API를 통해서 사용하고자 하는 클래스와 메소드를 다시 한번 확인해 봅니다.
보통 이경우 메소드의 철자나 대소문자를 잘못 쓴 경우가 많으니 그점을 유심히 살표봅니다.
마지막으로 철자와 대소문자도 맞는다면 메소드의 인자의 객체형을 맞게 주었는지 확인해보면 됩니다.
 

 

 

자바를 하다보면 에러와 만나게 되는데요... 자바는 친절해서 몇번라인에 에러가 났으니 고쳐달라고 콘솔창에 표시를 합니다... 그래도 모르는 에러들이 있는데요.. 조금이라도 참고해 보아요

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/11/07 03:03

1. 파일과 디렉토리 관리

가. 추상 경로명(abstract pathname)

UNIX 플랫폼 또는 Win32 플랫폼 등과 같은 각 운영체제는 파일과 디렉토리 이름에 시스템 의존적인 경로명(system-dependent pathname)의 문자열을 사용합니다. 이는 프로그램 개발자로 하여금 시스템에 일일이 신경쓰도록 해야 하고, 프로그램의 이식성 또는 상호호환성을 어렵게 하는 원인 중의 하나가 됩니다. 이러한 문제를 해결하기 위해, 다시 말해서 플랫폼 독립적인 파일 또는 디렉토리 관리 기능을 제공하기 위해, 자바에서는 File 클래스를 제공해 주고 있으며, 이 클래스는 추상적이고 시스템(플랫폼) 독립적인 관점의 계층적인 경로명을 제공하고 있습니다. 이러한 추상 경로명은 다음과 같은 두 가지 요소로 구성되어 있습니다.

            - 플랫폼 의존적인 prefix 문자열: UNIX 플랫폼 상에서의 루트 디렉토리를 나타내는 "/", 그리고 Win32 플랫폼 상에서는 디스크 드라이브명(disk-drive specifier) 또는 UNC 경로명을 사용할 경우에 사용하는 "\\" 등이 있습니다.

            - 파일 또는 디렉토리를 나타내는 경로명: 이름을 나타내는 0개 이상의 문자열입니다.

prefix 개념은 UNIX 플랫폼상에서의 루트 디렉토리와 Win32 플랫폼 상에서의 드라이브명(drive specifiers), 루트 디렉토리, 그리고 UNC 경로명을 다루기 위해 사용됩니다. 예를 들면, 다음과 같습니다.

            - UNIX 플랫폼: 절대 경로명의 prefix는 항상 "/"이고, 상대 경로명은 prefix를 갖지 않습니다. 이 때, 루트 디렉토리에 대한 자바의 추상 경로명은 prefix "/"와 빈 이름열(name sequence)을 갖습니다.

"/"

"/home/ywpark/"

            - Win32 플랫폼: 경로명의 prefix는 드라이브 문자와 ":"로 구성된 드라이브명(drive specifier)과 절대 경로명일 경우 "\" 등을 포함합니다. UNC 경로명의 prefix는 "\\"이고, 호스트이름과 공유 이름은 이름열의 처음에 나타나는 두 개의 이름입니다. 드라이브를 갖지 않는 상대 경로명은 prefix가 없습니다.

"\\D:\ "

"\\Park\mp3z"

추상 경로명 내의 마지막 이름을 제외한 각 이름은 디렉토리를 의미하고, 마지막 이름은 디렉토리 이름일 수도 있고 파일 이름일 수도 있습니다. 경로명 문자열을 추상 경로명으로 변환하거나 또는 추상 경로명으로부터 경로명 문자열로 변환하는 것은 시스템에 의존적입니다.

추상 경로명 또는 문자열 형태의 경로명은 절대 경로일 수도 있고 상대 경로일 수도 있습니다. 절대 경로명은 파일의 완전한 위치를 나타내므로 더 이상의 정보가 필요 업습니다. 반면, 반면, 상대 경로명이 가리키고 있는 파일은 다른 경로명에서 얻은 정보를 이용하여 그 위치를 얻을 수 있습니다. 일반적으로, java.io 패키지 내에 있는 클래스들은 항상 시스템 속성인 user.dir이 가지고 있는 현재 사용자 디렉토리(current user directory)로부터 상대 경로명을 얻습니다. 일반적으로, 현재 사용자 디렉토리는 자바 가상 머신이 시작된(invoked) 디렉토리입니다.

추상 경로명이 경로명 문자열로 변환될 때, 각 이름은 디폴트 구분자 문자를 이용하여  서로 구분됩니다. 디폴트 이름 구분자 문자(name-separator character)는 시스템 속성으로 file.separator에 정의되어 있습니다. 반면, 경로명 문자열이 추상 경로명으로 변환될 때, 경로명 내의 이름들은 디폴트 이름 구분자 문자 또는 시스템에 의해 지원되는 다른 이름 구분자 문자 등에 의해 구분되어 있습니다.

나. File 클래스

File 클래스는 파일 및 디렉토리를 관리할 수 있도록 기능을 제공해 주는 클래스입니다. File 클래스는 파일의 복사 또는 이름 변경 등의 조작을 할 경우에 사용될 뿐, 파일의 내용을 입출력 하기 위한 메소드를 제공해 주지는 않습니다. 자바에서는 모든 데이터의 입출력을 스트림에 기반하여 수행하므로, File 클래스 내부적으로 이러한 메소드를 구현할 필요가 없기 때문입니다. 입출력 스트림과 관련된 내용은 뒤에서 자세히 살펴보도록 하겠습니다. 그런데, 이러한 File 클래스의 인스턴스는 변경 불가능합니다. 다시 말해서, 한 번 생성되면, File 객체에 의해 표현되는 추상 경로명은 절대로 변하지 않습니다. File 클래스에는 다음과 같은 종류의 경로 구분자와 이름 구분자를 제공해 주고 있습니다.

            - static char separatorChar: 시스템에 해당하는 디폴트 이름 구분 문자로서, 시스템 속성인 file.separator의 값을 갖습니다.

UNIX 시스템: '/'

Win32 시스템: '\'

            - public static final String separator: 시스템에 해당하는 디폴트 이름 구분 문자(name-separator character)로서, 편의상 문자열로 표현되어 있습니다.

UNIX 시스템: "/"

Win32 시스템: "\"

            - public static final char pathSeparatorChar: 시스템에 해당하는 경로 구분 문자로서, 시스템 속성인 path.separator의 값을 갖습니다.

UNIX 시스템: ':'

Win32 시스템: ';'

            - public static final String pathSeparator: 시스템에 해당하는 경로 구분 문자(path-separator character)로서, 편의상 문자열로 표현되어 있습니다.

UNIX 시스템: ":"

Win32 시스템: ";"

File 클래스에는 다음과 같은 세 종류의 생성자가 있습니다. 각각에 대하여 간단히 살펴보도록 하겠습니다.

            - public File(String pathname): 주어진 경로명을 추상 경로명으로 변환하여 새로운 File 객체를 생성합니다. 만약, 주어진 문자열이 빈 문자열이라면, 빈 추상 경로명이 됩니다.

            - public File(String parent, String child): 두 개의 문자열에 주어진 경로명을 이용하여 새로운 File 객체를 생성합니다. parent 문자열이 null이면, child 문자열을 경로명으로 하는 객체를 생성하고, 그렇지 않을 경우 parent 문자열은 디렉토리를 나타내고, child 문자열은 디렉토리 또는 파일일 수 있습니다.

            - public File(File parent, String child): 주어진 File 객체와 문자열을 이용하여 새로운 File 객체를 생성합니다. parent 객체가 null이면, child 문자열을 경로명으로 하는 객체를 생성하고, 그렇지 않을 경우 parent 객체는 디렉토리를 나타내고, child 문자열은 디렉토리 또는 파일일 수 있습니다.

File 클래스에서 제공해주는 주요 메소드를 살펴보면, 다음과 같습니다.

            - public String getName(): 추상 경로명이 나타내는 파일 또는 디렉토리의 이름을 얻습니다. 이 이름은 경로명 이름에 있는 마지막 이름입니다.

            - public String getParent(): 추상 경로명의 부모 경로에 대한 경로명을 문자열로 얻습니다. 이 때, 부모 경로명은 추상 경로명이 갖는 prefix와 경로명에 있는 마지막 이름을 제외한 나머지 이름들을 포함하고 있습니다.

            - public File getParentFile(): 추상 경로명의 부모 경로에 대한 추상 경로명(File 객체)을 얻습니다. 이 때, 부모 경로명은 추상 경로명이 갖는 prefix와 경로명에 있는 마지막 이름을 제외한 나머지 이름들을 포함하고 있습니다.

            - public String getPath(): 추상 경로명을 경로명 문자열로 변환하여 얻습니다. 이 때, 디폴트 이름 구분 문자가 적용됩니다.

            - public boolean isAbsolute(): 절대 경로명인지를 얻습니다. UNIX 시스템 상에서는 prefix가 "/"를 포함하고 있을 경우, Win32 시스템 상에서는 prefix가 "\\"와 드라이브 문자 또는 "\\"를 포함하고 있을 경우 절대 경로명입니다.

            - public String getAbsolutePath(): 추상 경로명에 대한 절대 경로명을 문자열로 얻습니다. UNIX 시스템 상에서 상대 경로명일 경우, 현재 사용자 디렉토리와 결합하여 절대 경로명을 얻습니다. Win32 시스템 상에서의 상대 경로명은 드라이브 문자를 포함하여, UNIX 시스템과 마찬가지로 현재 사용자 디렉토리와 결합하여 얻습니다.

            - public File getAbsoluteFile(): "new File(this.getAbsolutePath()())"와 같습니다.

            - public String getCanonicalPath() throws IOException: 추상 경로명에 대한 유일한 정규 표현 경로명을 얻습니다.

            - public File getCanonicalFile() throws IOException: "new File(this.getCanonicalPath()())"와 같은 효과를 얻습니다.

            - public URL toURL() throws MalformedURLException: 추상 경로명을 URL로 변환하여 얻습니다.

            - public boolean canRead(): 파일이 읽기 가능한지를 얻습니다.

            - public boolean canWrite(): 파일이 쓰기 가능한지를 얻습니다.

            - public boolean exists(): 파일이 존재하는지를 얻습니다.

            - public boolean isDirectory(): 디렉토리인지를 얻습니다.

            - public boolean isFile(): 파일인지를 얻습니다.

            - public boolean isHidden(): 숨겨진(hidden) 파일인지를 얻습니다.

            - public long lastModified(): 파일이 마지막으로 갱신된 시간을 얻습니다.  시간은 epoch (00:00:00 GMT, January 1, 1970)로부터 경과된 밀리초를 나타내며, 값이 0L이면 파일이 존재하지 않거나 I/O 에러가 발생했음을 나타냅니다.

            - public long length(): 파일의 크기를 얻습니다.

            - public boolean createNewFile() throws IOException: 추상 경로명에 해당하는 파일이 존재하지 않는 경우 비어있는 새로운 파일을 생성합니다.

            - public boolean delete(): 추상 경로명이 가리키는 파일이나 디렉토리를 삭제합니다. 이 때, 비어있지 않은 디렉토리는 삭제할 수 없습니다.

            - public void deleteOnExit(): 가상 머신이 종료될 때, 이 추상 경로명이 나타내는 파일을 삭제되도록 요청합니다. 이 메소드에 의해 파일이 지워지도록 요청되면, 이 요청은 취소될 수 없을므로, 주의를 기울여서 사용해야 합니다.

            - public String[] list(): 추상 경로명이 나타내는 디렉토리 내의 파일과 디렉토리의 이름에 대한 문자열 배열을 얻습니다.

            - public File[] listFiles(): 추상 경로명이 나타내는 디렉토리 내의 파일과 디렉토리의 이름에 대한 File 객체 배열을 얻습니다.

            - public boolean mkdir(): 이 추상 경로명에 해당하는 디렉토리를 생성합니다.

            - public boolean mkdirs(): 이 추상 경로명에 해당하는 디렉토리를 생성가능한지를 얻습니다. 만약, 경로명의 부모 경로명이 존재하지 않을 경우도 고려됩니다.

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/11/05 10:22

1. Stream

  대부분의 언어에서 입출력을 수행하는 것은 결코 간단한 얘기는 아니다. 그러나 스트림을 지원하는 언어라면 조금은 얘기가 틀려진다. 스트림은 입출력을 위임받아 처리하는 하나의 단위를 의미하는데, 스트림의 정의는 바이트의 순차적 입출력 방식이다.

  이것은 입출력을 수행할 데이터를 바이트의 배열 형태로 바꾸어 입출력을 수행하는 방식으로 데이터가 순서대로 입력과 출력이 이루어진다는 말이다. 이 스트림 방식을 사용하게되면 하드웨어가 어떻게 바뀌더라도 일관된 방식으로 입출력을 수행할 수 있다.

  자바에서 입출력을 수행하기 위해 java.io 패키지로 제공되며 이 패키지를 이용하면 스트림 방식의 입출력이 가능하다.


2. InputStreamReader / OutputStreamWriter 클래스

  Reader와 Writer 클래스는 Object 클래스의 바로 하위 클래스이다. 이것들로부터 바이트 입출력 스트림 상속시켰는데, Buffered Reader/Writer와 InputStreamReader/Writer가 대표적이다.

  InputSreamReader와 Writer를 이용하여 바이트의 입출력을 수행해보자.

import java.io.*;

public class ReWriter {

        public static void main(String[] args) {

                InputStreamReader ir = new InputStreamReader(System.in);

                OutputStreamWriter or = new OutputStreamWriter(System.out);

               

                int temp;

                try{

                        while((temp=ir.read())!=-1)

                                System.out.println((char)temp);

                }catch(IOException e){}

        }

}

  위의 예에서 ir.read() 메서드의 리턴형은 byte형이다. 즉, 형 그대로 출력하게 되면 숫자가 나타나게 된다. 이것을 우리가 원하는 문자로 보여주기 위해서는 char형으로 캐스트 연산되어야 한다.

 

3. BufferedReader / BuffersWriter

  위의 방식에서 더욱 개선된 버퍼를 이용한 입출력 방식이다. 버퍼는 임시기억장치를 의미하는데 입출력 장치과 CPU 사이에서 위치해, 조금 더 효과적인 입출력을 지원하는 방식이다. 예를 들어 입출력 장치에서 입출력이 일어나면 CPU는 입출력이 완료될때까지 대기해야 하는데 버퍼를 사용함으로서 이러한 단점을 줄이면서, 버퍼에 줄을 저장할 수 있기 때문에 줄 단위 입출력이 가능하다.

import java.io.*;

public class StringInput {

        public static void main(String[] args){

                String inputString;

                String text="String Test..";

                try{

                        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

                        BufferedWriter bw = new BufferedWriter(

                        new OutputStreamWriter(new FileOutputStream(text)));

                        while((inputString = br.readLine()) != null)

                                bw.write(inputString + "\n");

                        bw.close();

                        br.close();

                }catch(IOExcetion e){}

        }

}


4. FileReader / FileWriter

  기본 문자 인코딩을 이용해서 파일의 입출력을 담당하는 클래스이다. 이 클래스를 사용하면 파일에 읽고 쓰는 것이 가능하다. 다음은 파일 복사의 예이다.

import java.io.*;

public class FileCopy {

  public static void main(String[] args) {

    try {

      FileReader input = new FileReader("FileCopy.java");

      FileWriter output = new FileWriter("Test.txt");

      int charsRead;

      while((charsRead = input.read()) != -1) {

        output.write(charsRead);

      }

      input.close();

      output.close();

    }

    catch(IOException e) {

      e.printStackTrace();

    }

  }

}


5. 직렬화(Serializable)

  직렬화란 객체를 입출력하기 위한 방식이다. 실제로 위까지의 예제는 모두 기본 데이터형므로 바이트의 배열형식으로 내보는 것이 그리 어려운 얘기는 아니었다. 그러나 객체를 바이트 형의 배열로 변환하는 것은 그리 간단한 얘기가 아니다.

  다행스럽게도 자바에서는 직렬화라는 방식의 객체를 바이트 배열로 변환해주는 클래스가 지원된다.

public class User {

        private int number;

        private String name;

        private String subject;

       

        public User(int number, String name, String subject){

                this.number = number;

                this.name = name;

                this.subject = subject;         

        }

       

        public void print(){

                System.out.println("번호 : "+number);

                System.out.println("이름 : "+name);

                System.out.println("학과 : "+subject);

        }

}


import java.io.*;

public class SerialTest {

        public static void main(String[] args) {

                FileOutputStream fs;

                ObjectOutputStream os;

                try{

                        fs = new FileOutputStream("Serial.ser");

                        os = new ObjectOutputStream(fs);

           

                    User ob1=new User(1, "홍길동", "컴퓨터");

                    User ob2=new User(2, "이순신", "수학과");

                    User ob3=new User(3, "김좌진", "전자과");

                       

                    os.writeObject(ob1);

                    os.writeObject(ob2);

                    os.writeObject(ob3);

                   

                    os.close();

                }catch(FileNotFoundException e){

            }catch(IOException e){}

        }

}

import java.io.*;

public class SerialTest {

        public static void main(String[] args) {

                FileInputStream fs;

                ObjectInputStream os;

                try{

                        fs = new FileInputStream("Serial.ser");

                        os = new ObjectInputStream(fs);

           

                    User ob;

                    while((ob=(User)os.readObject())!=null)

                        ob.print();

                   

                    os.close();

                }catch(FileNotFoundException e){

                }catch(ClassNotFoundException e){

            }catch(IOException e){}

        }

}

 


크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/29 11:47

1. super 키워드

  어떠한 클래스가 어떠한 부모로부터 상속받은 클래스라고 할 때, 부모 클래스를 지칭하는 키워드이다. this 키워드와 보통 비교해 설명하는데, this는 자신이 소속된 메서드를 호출하는 객체를 지칭하게 되지만, super는 자신이 소속되어 있는 클래스의 부모 클래스를 지칭하게 되는 것이다.



2. final 키워드

  final은 클래스명, 메서드명, 변수명 앞에 각각 올 수 있다. 이것은 어느 곳에 위치하느냐에 따라 의미가 달라진다.

1. 클래스명 앞에 붙는 경우

    final class A{ ... }

2. 메서드명 앞에 붙는 경우

    class A{

        final void add(){...}

        ...

    }

3. 변수명 앞에 붙는 경우

    class A{

        final float PI=3.14;

        ...

    }

  1번처럼 클래스명 앞에 final이 오게되면 A라는 클래스는 더 이상 상속될 수 없음을 의미한다. 2번 같은 경우 메서드명 앞에 오게되었는데 이럴경우는 add()메서드는 더 이상 오버라이딩 될 수 없음을 의미한다. 추상 메서드는 반드시 오버라이딩이 되어야 하기 때문에 추상 메서드 앞에는 final이 올 수 없다.

  3번의 경우를 보자. 3번은 변수명 앞에 왔는데 이럴 경우에는 앞에서 얘기했던 상수화가 이루어진다. 다시 얘기하자면, 상수는 변수와 다르게 값이 변경되지 않는 수를 의미한다. 상수명은 관례상 대문자로 기술하며, 선언 후에 변경될 수 없기 때문에 선언과 동시에 반드시 초기화가 이루어져야 한다.



3. 접근제한자

  우선 이 얘기를 하기 전에 먼저 클래스와 패키지에 대한 개념부터 정립하자. 자바에서 클래스는 하나의 파일로 가정한다. 예를 들어 지금까지 클래스명과 파일명을 같게 했고, 소스 파일을 컴파일한 후에 보면 파일명과 같은 이름으로 class파일이 생성되었음을 알고 있을 것이다. 즉, 하나의 클래스는 하나의 파일로 간주하게 되는 것이고, 이 클래스들의 집합을 패키지라고 하며, 윈도우로 따지자면 파일의 집합. 즉, 폴더(디렉토리)가 되는 것이다. 이 클래스와 패키지에 대해서는 뒤에 더 따질테니 현재는 이 정도만 잡고 넘어가자.

  접근제한자의 접근 허용 범위는 public->protected->생략->private 순이다.

  public - 모든 접근에 대해 허용하며, 멤버 메서드는 대부분 public으로 선언한다.

  protected - 같은 패키지/클래스에 대해 허용.

              외부패키지라도 상속받은 자식에 대해 허용

  생략 - 같은 패키지/클래스에서만 접근 가능

  private - 같은 클래스에서만 접근 가능.

            멤버 변수를 대부분 private으로 선언한다.

            또한 뒤에서 배울 내부 클래스도 접근가능하다.



4. static 키워드

class A{

    int garo;

    int sero;

    public static void main(String args[]){

        A ob1 = new A();

        A ob2 = new A();

    }

}

  위에서 ob1과 ob2는 각각 리턴 받는 주소가 다르다. 이것은 A의 공간이 서로 다른 주소에 생성되었기 때문이다. ob1.garo=20 했을 경우 ob2.garo의 값이 동시에 20으로 바뀌지 않는 것도 위와 같은 이유 때문이다.

  그러나 static으로 선언된 정적 멤버 변수/메서드는 그렇지가 않다. 이것들은 각각의 객체들이 값을 공유해서 사용하게 되며, 객체명으로 접근하기보다는 대부분 클래스명으로 접근하게 된다.

public class StaticEx {

    private static int number=0;

    private int number1=0;

    public StaticEx() {

        ++number;

    }

    public static void main(String args[]){

        StaticEx ob1 = new StaticEx();

        System.out.println(ob1.number+"번 객체 생성");

        System.out.println(ob1.number1+"번 객체 생성");

        StaticEx ob2 = new StaticEx();

        System.out.println(ob2.number+"번 객체 생성");

        System.out.println(ob2.number1+"번 객체 생성");

        StaticEx ob3 = new StaticEx();

        System.out.println(ob3.number+"번 객체 생성");

        System.out.println(ob3.number1+"번 객체 생성");

    }

}


5. Utility API

  유틸리티 API는 유틸리티를 모아놓은 패키지를 의미하는 것이다. java.util 패키지가 바로 그것인데, 이 패키지는 유틸리티를 모아놓다보니 클래스간의 연관성을 별로 없다. 그러나 이 클래스는 JDK1.1.x부터 지원되어왔던 것이고, 대부분의 자바 플랫폼에서도 별 무리 없이 사용할 수 있을 뿐더러, 상당히 유용한 기능들을 지원하므로 한번쯤 살펴보고 진행하자.


java.util 패키지의 주요 클래스들

 

컬렉션 프레임워크

Vector, Stack, HashTable

HashSet, TreeSet, ArrayList, LinkedList, HashMap, TreeMap

자원 관련

Locale, Proprties, ResoutceBundle, PropertyResourceBundle

시간, 날짜 관련

Date, GregorianCalendar

타이머

Timer, TimerTask

압축과 해제

zip.ZipInputStream, zip.ZipOutputStream

zip.jar.JarInputStream, zip..jar.JarOutputStream

기타

Arrays - 배열에 대한 정렬, 탐색 등의 부가 기능들 제공

 

StringTockenizer - 문자열을 토큰을 이용해서 분리


  1) Vector

    배열은 크기가 고정되어 있으며, 배열의 크기를 넘어설 수 없다. 그러나 Vector는 배열과 다르게 크기가 가변적이며, 필요시 크기를 늘려서 제한없이 사용할 수 있다. 따라서 크기를 알 수 없는 배열을 사용해야 할 경우 유리하다. 개수가 정해지지 않은 데이터를 한 곳에 모을 경우에는 편하지만 배열보다는 속도가 느리다. 벡터에서 전체 크기를 용량이라고 부르며, 저장된 객체를 합친만큼을 크기라고 부른다.

  벡터에서 원소의 저장은 add()메서드로 이루어지며 제거는 remove()메서드를 사용한다. 저장된 객체는 get(int index)를 통해 얻을 수 있는데 Object 리턴형을 가지므로 저장했던 원래의 클래스로 형변환후 사용해야 한다.

  객체를 자주 저장하거나 복원할 경우 속도를 증가시키기 위해서는 벡터를 생성할 당시 초기 크기나 증가량을 충분히 설정할 필요가 있다. 또한 많은 수의 객체를 저장하기 전에 ensureCapacity(벡터의 최소 용량) 메서드로 용량을 원하는 만큼 한꺼번에 키워주는 것도 권장한다. 용량에 여유가 있다면 버퍼에 할당하는 회수가 많이 줄어들기 때문에 속도를 높이는 한가지 방법이다.

public class User {

    private int number;

    private String name;

    public User(int number, String name){

        this.number=number;

        this.name=name;

    }

    public void print(){

        System.out.println(number+"번 이름 : "+name);

    }

}

import java.util.Vector;

public class VectorEx {

    public static void main(String args[]){

        Vector v = new Vector();

        User ob1 = new User(1, "홍길동");

        User ob2 = new User(2, "이순신");

        User ob3 = new User(3, "박문수");

        User ob4 = new User(4, "김유신");

        v.add(ob1);

        v.add(ob2);

        v.add(ob3);

        v.add(ob4);

       

        for(int i=0;i<v.size();i++){

            User ob = (User)v.get(i);

            ob.print();

        }

       

    }

}


  2) Hashtable

    해시 테이블은 키 값과 대응되는 값을 저장하는 구조체인 사전 기능을 구현한 클래스이다. 쉽게 생각하면 사전을 찾을때 단어를 찾아 단어의 뜻을 찾아내는 것과 같은 이치이다. 벡터는 인덱스라는 int형의 키를 가지고 있지만, 해시 테이블은 int형이 아닌 객체 자체를 키값으로 가질 수 있다는 장점이 있다.

  키 값과 대응 값이 하나씩 짝지어지는 것을 매핑이라고 하며, 해시 테이블의 매핑은 항상 한 키에 여러개의 대응되는 값이 있어서는 않된다. 만약 같은 킷값을 이용하여 저장하려고 할 경우 먼저 있던 값에 덮어씌워지는 결과를 초래하게 된다. 또한 vector와 마찬가지로 get을 하게되면 Object형으로 리턴된다. 그러므로 클래스형으로 변환하여 사용해야 한다.

  void clear() - 모든 킷값을 제거

  Enumeration keys() -  해시 테이블의 키 값을 돌려줌

  Enumeration elements() - 해시 테이블에 저장된 객체를 돌려줌

  Object get(Object key) - 주어진 키에 대응되는 값을 돌려줌

  Ojbect put(Object key, Object value) - 키와 대응하는 것을 저장한다

  int size() - 해시 테이블의 대응 관계의 개수를 리턴한다.


  3) Enumeration

    위에서 리턴형 중에 Enumeration 클래스가 존재하는데 이 클래스는 hasMoreElements와 nextElements 두 메서드를 가지고 있다. 이를 이용하면 다음의 예와 같이 객체를 모두 얻어낼 수 있다.

for(Enumeration enu=hashtable.key(); enu.hasMoreElements() ; )

    Object ob = hashtable.get(enu.nextElement());

  다음의 예는 HashTable과 Enumeration 클래스를 이용하여 전화번호부를 구성한 예이다.

import java.util.Hashtable;

import java.util.Enumeration;

public class HTEx {

    public static void main(String args[]) {

        Hashtable ht = new Hashtable();

        ht.put("홍길동", "3481-1001");

        ht.put("박문수", "3481-1002");

        ht.put("이순신", "3481-1003");

        System.out.println((String) ht.get("박문수"));

        for (Enumeration enu = ht.keys(); enu.hasMoreElements(); ) {

            String key = (String) enu.nextElement();

            String value = (String) ht.get(key);

            System.out.println("Key : " + key + " Value : " + value);

        }

        ht.clear();

    }

}

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/29 11:38

1. 배열의 선언과 사용

  Java에서 사용하는 배열은 C에서 사용했던 것과 비슷하다.

  자료형[] 배열명 = new 자료형[];

  위와 같이 선언하게 된다. 위와 같이 선언하는 방법을 동적할당이라고 하며, 자바에서는 동적할당을 기본으로 한다. 동적할당은 일반적인 정적할당과 달리 여러 가지 장점을 가지는데 그 중 하나가 컴파일시에 주소가 결정되는 것이 아닌 실행시에 결정된다는 장점이다. 그로 인해 많은 잇점을 얻을 수 있다. 또한 배열은 여러 가지 유용한 기능을 보유하고 있는데 아래의 예를 보자

public class ObjectA{

  public static void main(String args[]){

    String[] A = new String[3];

      A[0) = "이순신“;

      A(1) =“김좌진”;

      A(2) = "박문수“;

      System.out.println("크기 : " +A.length);

      A.sort();

      for(int i=0;i<A.length;i++)

        System.out.println("배열 "+i+" : "+ A[i]);

  }

}   

    위에서보면 배열명.length라는 변수와 배열명.sort()라는 메서드가 나왔다. 앞에는 배열의 크기를 알려주는 것이고, 두 번째는 배열안에 있는 요소를 정렬시키는 메서드이다. 이 둘은 배열을 사용하면서 우용하게 사용될 것이다.



2. 클래스 선언

  객체지향 프로그래밍은 항상 클래스 정의로부터 시작된다. 클래스를 정의하게 되면 정의된 클래스는 보통 Ojbect형이라고 하며, 최상위 클래스는 Object 자료형으로부터 상속받게 된다.

public class ObjectA{

  public int i; //멤버 변수

  public int j; //멤버 변수

  public void add(){ //멤버 메서드

    int k=i+j;

    System.out.println("k="+k);

  }

}

위와 같이 클래스가 선언되었다. 이 클래스는 ObjectA라는 이름을 가지며, ObjectA라는 자료형이 되었다. 그럼 위와 같이 클래스를 선언한다고해서 바로 사용할 수 있을까? 절대 그렇지 않다. 위와 같이 클래스를 선언했다고 해서 메모리에 할당된 것이 아니기 때문이다. 클래스를 사용하기 위해서는 객체를 선언해야 한다. 객체의 선언은

클래스명 객체명 = new 클래스명();

  혹은

  클래스명 객체명 = null;

  이라고 기술하면 된다.

  그럼 new 키워드가 하는 일에 대해서 살펴보자. new 키워드가 하는 역할은 =을 기준으로 오른쪽의 클래스 크기만큼 메모리 어딘가에 공간을 생성한 후, 객체명에게 이 주소를 리턴시켜준다. 이렇게 함으로서 객체명으로 객체의 멤버에 접근이 가능하게 된다.

public class ObjectEx{

  public static void main(String args[]){

    ObjectA ob = new ObjectA();

    ob.i = 19;

    ob.j = 20;

    ob.add();

  }

}



3. 생성자 메서드

  그럼 위의 예에서 객체를 선언할 때 쓰이는 문장 맨 뒤를 보자.

  클래스명 객체명 = new 클래스명();

  뒤에 클래스명() 에 붙는 가로의 역할이 바로 생성자 메서드 호출이다. 위에서 new가 하는 역할은 공간 할당 후 주소 리턴이라고 했다. 그러나 한가지 역할을 더 수행하게 되는데, 이것이 바로 생성자의 호출이다. 생성자 메서드를 정의해보자.

public class Con{

  public int garo;

  public int sero;

  public Con(int garo, int sero){

      this.garo=garo;

      this.sero=sero;

  }

  public void width(){

      int wid=garo*sero;

      System.out.println("넓이 : "+wid);

  }

}

  생성자는 위의 예제중 Con()이라는 메서드이다. 생성자 메서드의 특징은 리턴형이 없으므로, 리턴을 할 수가 없다는 것과 메서드명이 클래스명과 같다. 생성자 메서드는 객체의 초기화를 위에 대부분 사용되며, 위에서 사용된 this 키워드는 Con 메서드를 호출한 객체를 의미한다.

public class ConEx{

  public static void main(String args[]){

      Con ob = new Con(10, 20);

      ob.width();

  }

}



4. 클래스 상속

  우리가 흔히 상속이라고 하면 부모의 속성을 그대로 물려받는 것을 의미한다. 객체지향 프로그래밍에서도 역시 상속은 같은 의미로 사용된다. 부모 클래스로부터 파생시킨(상속시킨) 자식 클래스는 부모 클래스의 특성을 그대로 물려받게 된다. 이 상속은 매우 중요한 개념중의 하나로, 잘 알아두기 바란다. 상속은 이미 누군가 만들어놓은 클래스를 부모 클래스로해서 물려받아 사용하기 때문에, 부모 클래스를 재사용한다는 장점과 함께 자식 클래스에서 필요한 부분은 추가로 정의하게 되기 때문에 부모 클래스에서의 확장성이 있다.

public class Base{

  public int garo;

  public int sero;

  public Base(int garo, int sero){

    this.garo=garo;

    this.sero=sero;

  }

  public void width(){

    int wid=garo*sero;

    System.out.println("넓이 : "+wid);

  }

}

  위와 같이 부모 클래스를 만들었다. 그럼 부모 클래스로부터 상속받는 자식 클래스를 정의해보자.

public class BaseEx extends Base{

  public static void main(String args[]){

    BaseEx ob = new BaseEx(10,20);

    ob.width();

  }

}


크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/29 11:37

1. 오버로딩

오버로딩이란 메서드의 중복을 말하는데, 같은 이름으로 여러 역할을 하도록 만드는 기술이다. 예를 들어

public class Poly {

    public void width(int r){

        float wid=3.14f*r*r;

        System.out.println("원의 넓이 : " + wid);

    } 

    public void width(int garo, int sero){

        int wid=garo*sero;

        System.out.println("사각형의 넓이 : " + wid);

    }

    public static void main(String args[]){

        Poly poly = new Poly();

        poly.width(10);

        poly.width(20, 10);   

}


  위에서 width()를 보자. 그러면 width(r)과 width(garo, sero)가 보이는데 이 두 메서드가 오버로딩되었다고 말할 수 있는 것이다.

  만약 width(10)으로 호출하게 되면 이 10이라는 것을 받을 수 있는 int 형 중 인수가 하나이기 때문에 width 메서드 중 위에 것이 호출되게 된다. 이것은 절차지향 프로그래밍과는 달리 객체지향 프로그래밍에서는 메서드의 이름으로 메서드가 같은 지를 판단하는 것이 아닌 메서드 인수의 타입이나 개수로 판단하기 때문에 가능한 것이다.



2. 오버라이딩

  오버라이딩은 간단히 정의해서 부모 클래스에서 정의되어 있는 메서드를 같은 이름으로 다른 역할을 재정의하고 싶을때 사용하게 된다.

  객체지향 프로그래밍은 유지보수에 초점이 맞추어져 있다. 그러다보니 비슷한 역할이라는 메서드의 이름을 통일하는 것을 더욱 좋게본다. 예를 들어 넓이를 구하는 의미인데, 어떤 메서드에서는 'width'라는 이름을 사용하고 어떤 메서드에서는 '넓이'라는 이름을 사용하면 나중에 같은 의미지만 헤메이게 될 소지가 있기 때문이다. 그러면 아래의 예를 보자.

public class Poly {

    private int garo;

    private int sero;

    public Poly(int garo, int sero) {

        this.garo=garo;

        this.sero=sero;

    }

    public void width(){

        int wid=garo*sero;

        System.out.println("사각형의 넓이 : " + wid);

    }

}

public class Tri extends Poly {

    public Tri(int garo, int sero) {

        this.garo = garo;

        this.sero = sero;

    }

    public void width() {

        float wid=garo*sero*0.5f;

        System.out.println("삼각형의 넓이 : " + wid);

    }

    public static void main(String[] args) {

        Tri tri = new Tri(20, 10);

        tri.width();

    }

}


  위의 예에서 보듯, 부모에 있는 width는 사각형을 구하기 위한 메서드였다. 그러나 Poly로부터 상속받은 Tri에서는 삼각형을 구하고자 했다. 그렇기 때문에 width라는 이름으로 넓이를 통일시키고자 Poly의 width를 Tri에서 재정의를 통해 구현한 것이다.



3. 추상 클래스

  추상 클래스는 선언만 되어 있고, 구현은 되어 있지 않은 메서드를 추상 메서드라고 하는데 추상 메서드를 하나라도 포함하게 되는 클래스를 추상클래스라고 한다. 추상메서드와 클래스는 항상 abstract라는 키워드를 붙여 줌으로서 선언하게 된다. 그럼 추상 클래스를 왜 사용해야할까? 아래의 예를 보면서 얘기해보자.

public abstract class Poly {

    int garo;

    int sero;

    public abstract void width();

}


  우리는 Poly 클래스에 이미 가로와 세로가 선언되어져 있고, 사각형의 넓이를 구할 수 있는 메서드가 정의되어 있다는 것을 알고 Poly를 이용해서 사각형 뿐만이 아닌 삼각형의 넓이도 구하려고 한다. 그런데 Poly에서는 삼각형과 사각형의 공식이 서로 틀려 어떻게 구현되어야 할지 감을 잡을 수가 없다. 그렇기 때문에 상속받는 자식에서 구현하라는 의미로 우리는 여기서 선언만 되어 있는 width를 선언하게 된것이다. 그리고 abstract라는 키워드가 메서드와 클래스의 앞에 각각 붙어져 있는 것을 확인할 수 있다.

  가장 중요한 것은 추상 클래스로부터 상속받는 클래스에서는 추상 메서드는 반드시 오버라이딩 시켜서 사용해야 한다는 것이다. 그럼 상속받은 삼각형과 사각형 클래스를 각각 정의해보자.

public class Tri extends Poly {

    public Tri(int garo, int sero) {

        this.garo=garo;

        this.sero=sero;

    }

    public void width(){

        float wid=garo*sero*0.5f;

        System.out.println("삼각형의 넓이 : " + wid);

    }

    public static void main(String[] args) {

        Tri tri = new Tri(20, 10);

        tri.width();

    }

}

public class Rect extends Poly {

    public Rect(int garo, int sero) {

        this.garo=garo;

        this.sero=sero;

    }

    public void width(){

        int wid=garo*sero;

        System.out.println("사각형의 넓이 : " + wid);

    }

    public static void main(String[] args) {

        Rect rect = new Rect(20, 10);

        rect.width();

    }

}



4. 인터페이스

  자바에서는 원칙적으로 다중 상속을 금하고 있다. extends 키워드로는 두 개 이상의 클래스로부터 상속받을 수 없다는 의미이다. 그러나 다중 상속을 꼭 해야하는 경우가 있다. 이럴때 사용할 수 있는 것이 인터페이스이다. 인터페이스는 추상메서드와 변수가 아닌 상수만을 소유할 수 있다. 인터페이스에서 변수를 선언하게 되면 상수화되기 때문에 상수 선언시 값초기화를 해주어야 한다. 또한 인터페이스로부터 상속받을 때는 extends 키워드가 아닌 implements 키워드를 사용한다. 역시 인터페이스에 있는 추상메서드도 반드시 오버라이딩 시켜야 하며, 추상 메서드라고 해서 abstract를 붙이지는 않는다.

public interface Poly {

    float PI=3.14f;

    public void width(int r);

}

public class Circle implements Poly {

    public void width(int r) {

        float wid = 3.14f * r * r;

        System.out.println("원의 넓이 : " + wid);

    }

    public static void main(String[] args) {

        Circle circle = new Circle();

        circle.width(10);

    }

}


크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/29 11:34


5.1.1 추상클래스의 개념


Abstract클래스는 빈 깡통 클래스입니다. abstract클래스는 구현이 덜 되었거나 또는 아직은 미완성 클래스이기 때문에 우리는 이 클래스를 추상 클래스라 부릅니다. 어디가 미완성일까요? 미완성 메서드를 포함하고 있기 때문에 클래스자체가 미완성이 되는 것입니다. 미완성 메서드는 어디가 미완성일까요? 메서드의 몸체가 없습니다. 몸체 없는 메서드, 이를 우리는 추상 메서드라 부릅니다. 그리고 이 추상 메서드를 단 하나라도 포함하고 있는 클래스를 추상 클래스라고 합니다.

 

 

5.1.2 추상클래스와 추상메서드

 추상클래스는 미완성 클래스이기 때문에 약점이 있습니다. 완전한 클래스가 아니기 때문에 절대 객체를 생성하지 못합니다. 당연한 것 아니겠습니까? 완성되지 않은 클래스이니 객체를 만들 수 없다는 것은 이치에 합당합니다. 이 미완성 클래스를 어디에 사용할까요? 사용방법은 다음과 같습니다.(이해하기 편하게 추상클래스를 추상아버지클래스, 이를 상속 받는 클래스를 아들클래스라고 하겠습니다. )

 

n        추상아버지 클래스는 추상 메서드를 가지고 있습니다.

n        아들 클래스는 추상 아버지클래스로부터 상속 받습니다.

n        아들은 추상 아버지 클래스의 몸체 없는 메서드를 모두 메서드 재정의와 같이 다시 만듭니다. 이것을 우리는 구현한다고 말합니다. 몸체를 달아 주는 것입니다.

n        아들 클래스는 완성된 클래스이기 때문에 객체를 생성할 수 있습니다.

 

 다음은 추상 메서드를 만드는 방법을 보여 주고 있는 예입니다.

추상 메서드를 만드는 방법

abstract class 클래스이름 {

abstract 메소드선언;        // 메소드의 몸체는 없음

abstract 메소드선언;        // 메소드의 몸체는 없음

}

 

)

 

public abstract class AbstractTest {

   public abstract void abstractMethod();

}

 

메서드에 몸체가 붙지 않는다면 여러분은 반드시 abstract키워드를 붙여야 합니다. 그리고 이 abstract메서드를 하나라도 포함하고 있다면 클래스명 앞에 abstract를 붙여야 합니다. 안 붙이면 언제나 그런 것처럼 친절하게 에러를 발생 시킵니다. 아래의 에러는 추상클래스내에 추상 메서드에 abstract를 붙이지 않았을 때 발생하는 에러입니다.

 

C:\examples\5. Class for Polymorphism Java>javac AbstractTest.java

AbstractTest.java:2: missing method body, or declare abstract

        public void abstractMethod();

                    ^

1 error

 

아주 간단하죠. 추상 클래스는 그 자체로는 객체를 생성할 수 없다는 것을 한번 더 밝혀 두며 실제 이용하는 가장 간단한 예를 보도록 하겠습니다.

 

NewCan.java(추상 메서드를 만드는 방법)

public class NewCan extends EmptyCan{

             public void sound(){

                           System.out.println("EmptyCan:빈깡통은 소리가 요란하다");

             }

             public void who(){

                           System.out.println("EmptyCan:나는 빈깡통입니다.");

             }

             public void sayHello(){

                           System.out.println("NewCan:추상클래스 테스트입니다.");

             }

             public static void main(String args[]) {

                           NewCan ecm = new NewCan();

                           ecm.who();

                           ecm.sound();

                           ecm.sayHello();

             }

}

Empty.java(추상클래스)

public abstract class EmptyCan{  

   public abstract void sound();//몸체없음

   public abstract void who();//몸체 없음  

}

C:\examples\5. Class for Polymorphism Java>javac NewCan.java

 

C:\examples\5. Class for Polymorphism Java>java NewCan

EmptyCan:나는 빈깡통입니다.

EmptyCan:빈깡통은 소리가 요란하다

NewCan:추상클래스 테스트입니다.

 

추상클래스는 객체가 가지는 특성들을 추상화시켜 놓았을 뿐, 아직 구체화 시키지 못한 클래스이므로, 이 추상클래스를 상속하는 하위클래스에서 좀 더 구체화 시키도록 하는 방법을 사용합니다. 주의 할 것은 추상 메서드를 하나도 빼지 말고 전부 구현 해야 객체를 생성할 수 있습니다. 아들이 상속을 받아서 추상 메서드를 하나라도 남겨 두었다면 아들도 추상클래스가 됩니다. 부전자전이죠. 다음은 상속을 했지만 추상 메서드를 전부 구현 하지 않았다면 abstract클래스가 되는 것을 증명하는 예제입니다.

 

CompleteCan.java(추상 메서드를 만드는 방법)

public class CompleteCan extends IncompleteCan{

             public void who(){

                           System.out.println("EmptyCan:나는 빈깡통입니다.");

             }

             public void sayHello(){

                           System.out.println("NewCan:추상클래스 테스트입니다.");

             }

             public static void main(String args[]) {

                           CompleteCan cc = new CompleteCan();

                           cc.who();

                           cc.sound();

                           cc.sayHello();

             }

}

Incomplete.java(추상클래스)

public abstract class IncompleteCan extends EmptyCan{

             public void sound(){

                           System.out.println("EmptyCan:빈깡통은 소리가 요란하다");    

             }

}

Empty.java(추상클래스)

public abstract class EmptyCan{  

   public abstract void sound();//몸체없음

   public abstract void who();//몸체 없음  

}

C:\examples\5. Class for Polymorphism Java>javac EmptyCan.java

C:\examples\5. Class for Polymorphism Java>javac IncompleteCan.java

C:\examples\5. Class for Polymorphism Java>javac CompleteCan.java

C:\examples\5. Class for Polymorphism Java>java CompleteCan

EmptyCan:나는 빈깡통입니다.

EmptyCan:빈깡통은 소리가 요란하다

NewCan:추상클래스 테스트입니다.

 

추상메소드는 추상클래스와 마찬가지로 아직 구현이 이루어지지 않고 단지 그 메서드의 이름만 가지고 있다는 뜻입니다. 그래서 몸체가 없다고 말하고 있는 것입니다. 이것을 역으로 말한다면 추상메서드가 되려면 몸체가 없어야 한다라는 명제를 얻을 수 있습니다. 보통 우리가 전문적인 용어로 이야기 할 때 추상메서드는 메서드의 프로토타입만 가지고 있다라고 이야기 합니다. 

 

 

5.1.3 클래스의 구조를 디자인하기 위한 추상 클래스

 추상클래스는 클래스의 구조를 잡기 위한 방법으로 사용됩니다. 하나의 클래스를 만든다고 가정한다면 하나의 클래스에 모든 것을 전부 넣을 수는 없습니다. 이러한 방법은 별로 좋지 않은 방법이죠. 클래스가 크다고 가정한다면 작업별로 클래스를 쪼개게 됩니다. 작업을 분할 하는 것은 수평적인 개념에서 비슷한 작업끼리 묶는 것입니다. 유유상종(類類相從)이라는 말이 적당할 것 같군요. 비슷한 작업끼리 묶어서 작업별 클래스를 만드는 것입니다.

 

저 또한 초보시절의 자바 프로그램은 비슷한 작업을 묶는 것으로 시작했습니다. 하지만 수평적으로 묶는 것 조차도 작업의 설계와 분석을 해야만 이루어지는 아주 어려운 일입니다. 이 단계를 거치고 나면 작업을 레벨단위로 묶는 것을 생각하게 됩니다. 거의 1년 이상 걸리더군요. 제가 머리가 나빠서 그런지도 모르겠지만 개인적으로는 상당히 어려운 일이었습니다. 레벨 단위의 작업으로 발전하기까지는 상당히 많은 시간과 생각이 필요한 것 같습니다. 작업을 단계별로 만들어 주는 역할을 하는 것이 바로 추상 클래스의 역할입니다.

레벨 단위의 구조를 살펴 보도록 하죠.

위의 그림은 도형을 그리기 위한 클래스를 디자인 하고 있습니다. 모든 클래스에서 공통되는 작업을 상위레벨에 놓고 그 클래스를 상속 받아 각각의 다른 클래스로 분류되어지고 있습니다. 상위레벨에 존재하는 작업은 구현할 필요성이 없다고 생각하여 abstract으로 만듭니다. 즉, 하위레벨에서 구현하겠다는 것입니다. 이렇게 하였을 때의 코드를 직접 만들어 보겠습니다. 물론 Shape클래스는 abstract으로 만들어질 것이며 그 하위의 Circle, Triangle, Rectangle은 모두 Shape의 abstract메서드를 구현 할 것입니다. 구현은 대충 아래와 같이 되어 질 것입니다.

 

FigureTest.java(abstract의 레벨기법을 테스트하기 위한 예제)

abstract class Shape {

             public abstract void draw();

             public abstract void delete();

}

class Circle extends Shape {

             public void draw(){

                           System.out.println("원을 그립니다");           

             }

             public void delete(){

                           System.out.println("원모양을 지웁니다");     

             }

}

class Triangle extends Shape {

             public void draw(){

                           System.out.println("삼각형을 하나, 둘, 셋, 그립니다.");          

             }

             public void delete(){

                           System.out.println("삼각형을 지웁니다");     

             }

}

class Rectangle extends Shape {

             public void draw(){

                           System.out.println("사각형을 원, 투, 쓰리, 포 그립니다.");     

             }

             public void delete(){

                           System.out.println("사각형을 지웁니다");     

             }

}

//abstract을 테스트하기 위한 클래스

public class FigureTest{

             public static void main(String[] args){

                           Circle c = new Circle();

                           Triangle t = new Triangle();

                           Rectangle r = new Rectangle();

                           c.draw();

                           t.draw();

                           r.draw();

                           c.delete();

                           t.delete();

                           r.delete();

             }

}

C:\examples\5. Class for Polymorphism Java>javac FigureTest.java

C:\examples\5. Class for Polymorphism Java>java FigureTest

원을 그립니다

삼각형을 하나, 둘, 셋, 그립니다.

사각형을 원, 투, 쓰리, 포 그립니다.

원모양을 지웁니다

삼각형을 지웁니다

사각형을 지웁니다

 

상속과 abstract을 설명하기 위해서 어디서나 흔히 볼 수 있는 예제입니다. 이 간단한 예제가 무엇을 의미하는지 제대로 안다면 자바의 강력한 힘을 발휘할 수 있습니다. 클래스의 수평적인 작업 분할과 수직적인 작업 분할을 동시에 이용한다면 여러분은 아주 효율적인 코드를 작성할 수 있습니다. 재사용성 100%와 유지, 보수, 관리 능력까지 갖춘 잘 설계된 프로그램을 하실 수 있을 것입니다.

 

 

5.1.4 결론

추상클래스에 대하여 정리 해 보죠.

 

n         추상 메서드는 몸체 없는 프로토타입만을 가진 메서드입니다.

n         추상 메서드는 반드시 메서드이름 앞에 abstract 키워드를 명시해야 합니다.

n         추상 메서드를 단 하나라도 포함하고 있으면 이를 추상 클래스라고 합니다.

n         추상 클래스는 클래스이름 앞에 abstract를 명시해야 합니다.

n         상속을 이용하여 추상 메서드를 모두 구현한 뒤, 객체를 생성할 수 있습니다.

 

일반적인 특징은 이러하지만 추상클래스의 뒷면에 존재하는 느낌은 수직적인 작업의 분할이라는 아주 무서운 개념이 숨어 있습니다. 프로그램을 하면서 어떻게 계층적으로 프로그램을 할지를 결정하지말고 펜을 들고 작업을 분석하는 것이 옳을 것입니다. 그리고 작업 분석이 끝났다면 수직과 수평의 개념을 적용 시켜서 어느 정도 설계를 하는 것이 옳을 것입니다. 하지만, 기본적인 배경 없이는 아무것도 할 수 없으니 지금은 느낌을 얻으시기 바랍니다.

 

여러분이 클래스를 만들고 시간이 지나서 다시 여러분이 만든 클래스를 볼 기회 있을 것입니다. 절대 같은 디자인의 클래스는 만들 수 없습니다. 물론, 클래스를 만드는 기법은 비슷하지만 같은 디자인으로는 프로그램을 하려고 해도 잘 되지 않습니다. 약간의 시간이 지난 후, 과거와 현재를 비교해 보면 여러분 스스로 진화했다는 말을 사용해도 될 만큼 아주 많은 발전을 이룬 것을 볼 날이 있을 것입니다.

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/29 11:22

final 키워드는 대개 정적인 방식으로 많이 쓰입니다. 예를 들어 클래스 상수로 쓰이거나, 클래스의 상속이나 메소드 재정의(overriding)을 막기 위해서 자주 사용되죠.

상대적으로 잘 쓰이지 않지만, 초기화 이후에 값을 바꿀 수 없는 변수를 만드는 동적인 용도로도 사용이 가능합니다. 자바 언어 레퍼런스를 보면 다음과 같이 내용이 있습니다:

A variable can be declared final. A final variable may only be assigned to once. It is a compile time error if a final variable is assigned to unless it is definitely unassigned immediately prior to the assignment.

C나 C++에 const라는 키워드가 있는데 변수에 대해서는 final보다 const가 더 적절한 이름이라고 생각합니다. 하지만, 클래스나 메소드 정의에 부여하는 경우는 final이 아주 좋다고 생각합니다.

배열을 인자로 받아서 합계를 내는 함수가 있다고 해보죠.

int sum(int[] a) {
  int result = 0;
  for (int i : a)
       result += i;
  return result;
}

이 경우 어떤 이유에서건 아래와 같이 구현된다면 해당 메소드를 사용자 입장에서는 의도하지 않은 결과를 접하게 될 가능성이 높습니다.

int sum(int[] a) {
 int[] others = {-1, -2, -3};
 a = others;
 int result = 0;
 for (int i : a)
  result += i;
 return result;
}

간단한 예를 통해서 보면 완전히 어리섞은 구현이긴 합니다. 하지만, 테스트가 없이 장문의 타이핑을 하는 환경에서는 이와 유사한 일이 일어나지 말라는 법은 없습니다.

int sum(final int[] a) {
  int result = 0;
  for (int i : a)
       result += i;
  return result;
}

이와 같이 정의해주면 적어도 a에 새로운 할당을 시도할 수 없게 됩니다.

3 + 4 = ?

위와 같이 더하기라는 연산을 할 때 피 연산자인 3과 4는 변하지 않습니다. 3과 4가 변한다면 사람들은 위험해서(?) 덧셈을 하지 않겠죠. :)

sum()에 인자로 제공해주는 것은 피연산자와 같습니다. 의미적으로 상수가 전달되어야 하는 경우라고 할 수 있죠. 이럴 때 final을 붙여주면 보다 의미가 명확해질 수 있습니다.

아래와 같은 구문에 왜 final을 쓰면 안되느냐는 질문을 받은 일이 있습니다.

int sum(int[] a) {
  final int result = 0;
  for (int i : a)
       result += i;
  return result;
}

자칫 범하기 쉬운 오류지만, result라는 변수의 용처를 명확하게 정립해보면 논리적인 오류임을 알 수 있습니다. result는 말 그대로 임시 저장소입니다. 지역 변수(local variable)은 임시(temp/temporary) 변수라고 하는데 딱 어울리는 용도로 사용한 것이죠.

세로 타원으로 그린 것이 for 문의 실행시의 논리적인 영역을 나타냅니다. 문맥(context)이라고 할 수도 있겠죠.  반복이 진행되면서 우측으로 이동하기 때문에 배열의 요소들의 이전 값을 기억하기 위해서는 별도의 저장소가 요구됩니다. 어떤 프로그래밍 언어를 배우거나 초기에 익히는 것이지만, 논리적으로 이러한 그림을 머리속에 그릴 수 있다면 더욱 복잡한 경우를 포용할 때 매우 유리합니다.

위와 같은 경우 a[0]의 값이 temp에 들어가 있어야 하고, 반복이 한 차례 더 수행되면 temp 값에 a[1]을 더한 값이 다시 할당되어져야 하니 final로 정의하는 것은 실수죠.
크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/29 11:17

클래스는 크게 일반클래스와 추상클래스로 나뉘는데 추상클래스는 본문중에 '추상메소드'가 하나 이상 포함되는 경우를 말합니다. 인터페이스는 모든 메소드가 추상메소드인 경우 선언하는 경우가 많습니다.


추상메소드라 함은 메소드의 선언부만 있고 본문이 없는 것을 말합니다. 여기서 본문은 중괄호({})로 묶여진 몸체(body)부분을 말하는데 중괄호 안이 비어있더라도 이것이 존재한다면 그것은 추상메소드가 아닙니다. 추상메소드의 선언의 예는 다음과 같습니다.


abstract public void test( int a );


즉, 메소드의 선언 후에 세미콜른(;)만을 찍어 이를 선언만 하고 구현은 자식클래스에서 하게 하는 방법입니다. 일반 클래스의 경우 상속받은 자식클래스가 반드시 부모클래스의 메소드를 '오버라이딩(overriding)'할 필요가 없지만 추상클래스를 상속받은 자식클래스는 반드시 추상메소드를 오버라이딩하여야 하기에 메소드를 강제로 구현하게 할 때 많이 쓰입니다.


추상클래스와 인터페이스의 가장 큰 차이점은 바로 '클래스'냐 아니냐의 차이입니다. 추상클래스는 엄연한 클래스로 이를 구현하는 것은 '상속(extends)'입니다. 그러나 인터페이스는 '포함(implements)'라는 키워드를 통해 구현하게 되는데 이는 자바에서 매우 중요한 차이를 가집니다.


자바는 오로지 '단일 상속'만을 지원하기 때문에 추상클래스를 상속받는 클래스는 다른 클래스를 상속받을 수 없습니다. 그러나 인터페이스를 포함하는 클래스는 다른 클래스를 상속받을 수 있습니다.


추상클래스는 일반클래스와 달리 그 자신을 new 명령어를 통해 객체를 생성할 수 없습니다. 그러나 '다형성(polymorlphism)'을 통해 자식 클래스의 객체를 생성할 수는 있습니다.


인터페이스를 쓰는 가장 큰 이유는 다중상속을 지원하지 않는 자바에서 다중상속의 장점을 가져오기 위해서입니다. 다중상속이 가지는 단점은 배제하고 오직 장점만을 취하기 위해 인터페이스를 쓰는 것입니다.


상속이란 개념은 부모클래스의 속성과 메소드를 자식클래스가 물려받는다는 것인데 쉽게 예를 들면 '자동차'라는 클래스는 '색깔', '배기량' 등의 속성과 '기름을 넣는다', '달린다' 등의 메소드를 가질 수 있습니다. 이 클래스를 상속하는 '승용차' 클래스는 별도로 선언하지 않아도 부모클래스의 '색깔', '배기량'이라는 속성과 '기름을 넣는다', '달린다'라는 메소드를 가지게 되죠.


추상클래스는 이 부모클래스가 단순히 관념적인 성격이 강할 때 많이 쓰이는데 예컨데 '새'라는 클래스는 그냥 '난다'라는 메소드를 가지지만 새의 종류에 따라 나는 방법이 조금씩 틀려 자식클래스에서 어차피 구현해야 될 부분이므로 굳이 부모클래스에서 그 내용을 구현할 필요가 없기 때문에 사용합니다.


요사이 추세는 굳이 클래스간의 조직을 표현할 필요가 없을 경우는 추상클래스를 쓰는 대신 인터페이스를 쓰는 경우가 많습니다. 인터페이스는 위에서 말씀드린바와 같이 모든 메소드가 추상메소드라서 이를 포함하는 클래스는 이들을 모두 구현해야 합니다.


추상메소드는 멤버변수(어트리뷰트)를 가지지만 인터페이스는 오직 '상수'만을 가질 수 있습니다.

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/29 10:37

■ Enumeration인터페이스

   벡터와 같이 객체들을 모아 놓은 집합에서 객체들을 하나씩 처리할 수 있는 메소드를 다음

   과 같이 제공한다.


    - boolean hasMoreElements()

       벡터에 요소가 있으면 true, 없으면 false를 반환한다.
   - Object nextElement()
       벡터에서 다음의 요소를 반환한다.
 
 
ExecuteEnumeration.java
 
import java.util.*;
class ExecuteEnumeration
{
   public static void main(String args[]){
      int j;
      Vector v=new Vector();
      for(j=0; j<args.length; j++)
         v.addElement(args[j]);
// java ExecuteEnumeration  Head     Title     100     30.5

//  ┌---------------------------------------------------┐

//  ㅣ Head ㅣ Title ㅣ 100 ㅣ 30.5 ㅣ  ㅣ   ㅣ  ㅣ   ㅣ   ㅣ   ㅣ

//  └---------------------------------------------------┘

//        ↑

//        v

      Enumeration enu = v.elements();

//  ┌----------------------------┐

//  ㅣ Head ㅣ Title ㅣ 100 ㅣ 30.5  ㅣ

//  └----------------------------┘

//        ↑

//     v=enu


      for(j=0; enu.hasMoreElements(); j++)
         System.out.println("Vector "+j+"번째 요소는 "+enu.nextElement());

// for문을 while문으로 고쳤을 경우,

//   j = 0;

//   while(enu.hasMoreElements()){

//           System.out.println("Vector "+j+"번째 요소는 "+enu.nextElement());

//    j++;

//    }
   }
}


크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/19 16:32
  == 는 주로 primitive data type간의 비교를 위해 사용합니다.
 예를 들어
int x = 1;
int y = 1;
일 경우 x == y 는 참이 됩니다.

 하지만 두 객체를 비교 했을 경우 == 는 가리키고 있는 객체의 레퍼런스 값이 같아야 참의 값이 나옵니다.

 반면 equals() 메서드는 값의 비교가 아닌 내용상의 비교이기 때문에
 해당 객체의 내용이 같다면 레퍼런스하고 있는 위치(주소값)이 달라도 원래 의도하신대로 같은 값을 얻을수 있습니다.

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

String s1 = "하하하";
String s2 = "하하하";
String s3 = new String("하하하");
String s4 = new String("하하하");

equals는 객체가 가지고 있는 내용을 비교하기 위한 메소드이며
==는 객체가 같은지 다른지 비교하는 비교연산자

if(s1 == s2)           // true
if(s1 == s3)           // false
if(s1.equals(s2))   // true
if(s3 == s4)           // false
if(s3.equals(s4))   // true
크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/17 00:22

●벡터(Vector)

   1. 대용량의 데이터를 효과적으로 다룰 있는 클래스

   2. 용량의 변경이 용의

   3. 벡터에 저장하는 모든 데이터는 Object타입

   4. 어떤 종류의 객체도 함께 담을 있다.

   +++ 배열의 크기를 한번 정해지면 변경 불가하고 같은 종류의 데이터만

        사용할 있다는 단점 보안

 

벡터 생성자

   1. Vector :  초기용량이 10, 용량 초과시 크기를 두배 증가

   2. Vector(int aaa) : 지정한 크기의 용량으로 초기화된 Vector 객체를 생성한다.

   3. Vector(int aaa, int bbb) : 지정한 크기의 용량으로 초기화된 벡터객체를 생성하고

                                          용량 초과시 bbb만큼 증가 시킨다.

일반적으로 용량의 문제가 거의 발생하지 않기 때문에 보통 인자가 없는

    생성자를 사용하여 벡터 객체를 생성한다.      Vector v = new Vector();

 

●벡터에 객체 저장

  메소드

   1. void add(int index, Object object) - 지정한 인덱스의 위치에 객체를 추가함

   2. void addElement(Object objec) - 벡터의 끝에 객체를 추가한다

        Vector v = new Vector();

        v.add(1, "은주");             //지정한 위치에 객체 추가

        v.addElement("현규");     //마지막에 객체 추가

        v.addElement("수미");     //마지막에 객체 추가

 

●벡터로 부터 객체 삭제

  메소드

1.       Object remove(int index) – 지정한 위치의 객제를 벡터에서 제거

2.       boolean remove(Object object) – 지정한 객체를 벡터에서 제거

3.       void clear() – 벡터의 모든 요소를 제거

) Vector v = Vector();            //벡터 생성

   v.remove(3);                        //지정한 위치의 객체 제거

   v.remove(“은주”);            //지정한 객체 제거

   v.clear();                        //벡터의 모든 요소를 제거

 

●벡터로 부터 객체 검색

  메소드

1.       Object elementAt(int index) – 지정한 위치의 객체를 리턴

2.       Object get(int index) – 지정한 위치의 객체를 리턴

벡터에 요소를 추가할 때는 String형을 그대로 사용할 있지만 검색한 결과는 Object형이므로 사용하기 위해서는 원래 데이터형으로 캐스팅해야 한다.

) Vector v = Vector();                        //벡터 생성

   String s = (String)v.elementAt(0);            //지정한 위치의 객체를 리턴

   String s2 = (String)v.get(1);                   //지정한 위치의 객체를 리턴

   Enumeration e = v.elements();            //Vector 요소의 리스트를 리턴

    Iterator 비슷한 역할(저장 객체 추출)

 

 

●벡터의 기타 메소드

1.      int capcity() – 벡터의 현재 용량의 리턴

2.      boolean contains(Object object) – 주어진 요소가 벡터에 있는지 알아낸다.

3.      int indexof(Object object) – 주어진 요소의 위치를 리턴(없으면 -1)

4.      int size() – 벡터에 포함되어 있는 요소의 수를 리턴

5.      void trimToSize() – 벡터의 용량을 현재 벡터의 크기에 맞게 수정

 

Enumeration

벡터에 저장된 객체를 열거형으로 리턴

  Enumeration e = v.elements();               //Vector 요소의 리스트를 리턴

     While(e.hasMoreElements()) {

    System.out.println(e.nextElement());

}

 

Iterator

Collection 저장된 객체를 나열 또는 열거하기 위한 인터페이스

  Iterator ie = v.iterator();         //Vector 요소의 리스트를 리턴

  While(ie.hasNext()){

    System.out.println(ie.next());

}

 

Stack

1.      Object 저장하는 하나의 방법

2.       가장 나중에 들어간 데이터가 가장 먼저 밖으로 나오는 형태

LIFO(Last In First Out)

) import java.util.*;

public class StackTest{

public static void main(String[] args){

      Stack s = new Stack();

      System.out.println(s.empty());           //스택이 비어있는지 확인 true

      s.push(“은주”);           //데이터 넣기

      s.push(“현규”);

      System.out.println(s.empty());           //false

      System.out.println(s.peek());   //가장 먼저 나올 데이타(은주)

      System.out.println(s.pop());           //스택에 저장 되어 있는 차례로 출력

      System.out.println(s.pop());

      System.out.println(s.empty());            //스택이 비어있는지 확인 true

}

}

 

LinkedList

1.      List 인터페이스의 링크 리스트의 구현

2.      void add(int index, Object element) – 지정된 위치에 지정된 요소 삽입

void addLast(Object element) – 리스트의 마지막에 지정된 요소 추가

Object get(int index) – 지정된 위치에 있는 요소 리턴

Object getLast() – 리스트내의 마지막 요소 리턴

Object remove(int index, Object element) – 지정된 위치에 있는 요소 삭제

3.      데이터의 첨가, 삭제가 편리하고 속도가 빠르다.

 

Map & hashing

키와 값의 쌍으로 이루어진 요소를 저장하는 자료구조

해싱이란 키객체를 처리하여 hash code(정수값) 만들어 내는 방법이다.

 

HashMap

Null허용, Map interface implements 클래스

 

Hashtable

Null 허용하지 않음, Map interface implements 클래스

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/16 12:10

자바를 한번쯤 공부해본사람이라면 static키워드를 모르지는 않을 것입니다.

하지만, 바르게 알고 있는 사람들은 그리 많지 않습니다.


자바경력자를 면접볼 때 static키워드에 대해서 질문하곤 합니다.


면접관 : static키워드에 대해서 설명해보세요.
응시자 : static키워드를 쓰면, 객체를 생성하지 않고도 변수나 함수를 사용할 수 있습니다.


면접관 : 왜 static키워드를 쓰나요?
응시자 : 객체를 생성하지 않아도 되니까 편리하고 속도도 빠릅니다.


면접관 : 그렇다면 모든 변수와 함수에 static을 붙이는 것이 좋겠네요?
응시자 : 가능한한 static을 붙이는 것이 좋다고 생각합니다.


면접관 : 어떤 경우에 static을 붙일 수 있고, 어떤 경우에 static을 붙일 수 없습니까?
응시자 : ...


면접관 : 만일 당신이 새로운 클래스를 작성한다고 할 때, 어떤 경우에 static키워드를
             사용해야한다고 생각합니까?

응시자 : ...


대부분의 경우 위와 같은 내용으로 문답이 진행됩니다.

사실 응시자의 대답은 다 맞는 얘기입니다. 하지만, static의 핵심적인 개념을 모르기 때문에
어떤 경우에 왜 static을 사용해야하는지는 잘모르는 것 같습니다.


먼저 결론부터 간단히 정리하면 다음과 같습니다.


1.클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통적으로 사용해야하는 것에 static을 붙인다.
 - 인스턴스를 생성하면, 각 인스턴스들은 서로 독립적기 때문에 서로 다른 값을 유지한다.
    경우에 따라서는 각 인스턴스들이 공통적으로 같은 값이 유지되어야 하는 경우 static을
    붙인다.


2. static이 붙은 멤버변수는 인스턴스를 생성하지 않아도 사용할 수 있다.
 - static이 붙은 멤버변수(클래스변수)는 클래스가 메모리에 올라갈때 이미 자동적으로
   생성되기 때문이다.


3. static이 붙은 메서드(함수)에서는 인스턴스 변수를 사용할 수 없다.
 - static이 메서드는 인스턴스 생성 없이 호출가능한 반면, 인스턴스 변수는 인스턴스를
    생성해야만 존재하기 때문에... static이 붙은 메서드(클래스메서드)를 호출할 때
    인스턴스가 생성되어있을수도 그렇지 않을 수도 있어서 static이 붙은 메서드에서
    인스턴스변수의 사용을 허용하지 않는다.
    (반대로, 인스턴스변수나 인스턴스메서드에서는 static이 붙은 멤버들을 사용하는 것이
     언제나 가능하다. 인스턴스변수가 존재한다는 것은 static이 붙은 변수가 이미 메모리에
     존재한다는 것을 의미하기 때문이다.)


4. 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.
 - 메서드의 작업내용중에서 인스턴스 변수를 필요로 한다면, static을 붙일 수 없다.
    반대로 인스턴스변수를 필요로 하지 않는다면, 가능하면 static을 붙이는 것이 좋다.
    메서드 호출시간이 짧아지기 때문에 효율이 높아진다.
    (static을 안붙인 메서드는 실행시 호출되어야할 메서드를 찾는 과정이 추가적으로
    필요하기 때문에 시간이 더 걸린다.)


5. 클래스 설계시 static의 사용지침
 - 먼저 클래스의 멤버변수중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지
    살펴보고 있으면, static을 붙여준다.
 - 작성한 메서드 중에서 인스턴스 변수를 사용하지 않는 메서드에 대해서 static을
    붙일 것을 고려한다.
 
일반적으로 인스턴스변수와 관련된 작업을 하는 메서드는 인스턴스메서드(static이 안붙은
메서드)이고 static변수(클래스변수)와 관련된 작업을 하는 메서드는 클래스메서드(static이 붙은 메서드)라고 보면 된다.


다음은 static에 대한 자세한 설명과 예제입니다.


static은 객체지향개념을 이해하는 가장 중요한 첫걸음이니 확실히 알아두셔야합니다.


==================================================================
   


 

3.2 클래스변수와 인스턴스변수


클래스변수와 인스턴스변수의 차이를 이해하기 위한 예로 카드 게임에 사용되는 카드를 클래스로 정의해보자.



카드 클래스를 작성하기 위해서는 먼저 카드를 분석해서 속성과 기능을 알아 내야한다. 속성으로는 카드의 무늬, 숫자, 폭, 높이 정도를 생각할 수 있을 것이다.
이 중에서 어떤 속성을 클래스 변수로 선언할 것이며, 또 어떤 속성들을 인스턴스 변수로 선언할 것인지 생각해보자.


class Card {
     String kind ;                         // 카드의 무늬 - 인스턴스 변수
     int number;                         // 카드의 숫자 - 인스턴스 변수
     static int width = 100 ;             // 카드의 폭 - 클래스 변수
     static int height = 250 ;            // 카드의 높이 - 클래스 변수
}


각 Card인스턴스는 자신만의 무늬(kind)와 숫자(number)를 유지하고 있어야 하므로 이들을 인스턴스변수로 선언하였고, 각 카드들의 폭(width)과 높이(height)는 모든 인스턴스가 공통적으로 같은 값을 유지해야하므로 클래스변수로 선언하였다.

만일 카드의 폭을 변경해야할 필요가 있을 때는 모든 카드의 width값을 변경하지 않고, 한 카드의 width값만 변경해도 모든 카드의 width값이 변경되는 셈이다.

[예제6-4] CardTest.java

class CardTest{
      public static void main(String args[]) {
            // 클래스변수(static 변수)는 객체생성없이 '클래스이름.클래스변수'로 직접 사용 가능하다.
            System.out.println("Card.width = " + Card.width);
            System.out.println("Card.height = " + Card.height);

            Card c1 = new Card();
            c1.kind = "Heart";
            c1.number = 7;

            Card c2 = new Card();
            c2.kind = "Spade";
            c2.number = 4;

            System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 (" + c1.width + ", " + c1.height + ")" );
            System.out.println("c2는 " + c2.kind + ", " + c2.number + "이며, 크기는 (" + c2.width + ", " + c2.height + ")" );             System.out.println("이제 c1의 width와 height를 각각 50, 80으로 변경합니다.");
            c1.width = 50;
            c1.height = 80;

            System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 (" + c1.width + ", " + c1.height + ")" );
            System.out.println("c2는 " + c2.kind + ", " + c2.number + "이며, 크기는 (" + c2.width + ", " + c2.height + ")" );
      }
}

class Card {
     String kind ;                         // 카드의 무늬 - 인스턴스 변수
     int number;                         // 카드의 숫자 - 인스턴스 변수
     static int width = 100;             // 카드의 폭 - 클래스 변수
     static int height = 250;             // 카드의 높이 - 클래스 변수
}

[실행결과]
Card.width = 100
Card.height = 250
c1은 Heart, 7이며, 크기는 (100, 250)
c2는 Spade, 4이며, 크기는 (100, 250)
이제 c1의 width와 height를 각각 50, 80으로 변경합니다.
c1은 Heart, 7이며, 크기는 (50, 80)
c2는 Spade, 4이며, 크기는 (50, 80)


Card클래스의 클래스변수(static변수)인 width, height 그리고 color는 Card클래스의 인스턴스를 생성하지 않고도 '클래스이름.클래스변수'와 같은 방식으로 사용할 수 있다.
Card인스턴스인 c1과 c2는 클래스 변수인 width와 height를 공유하기 때문에, c1의 width와 height를 변경하면 c2의 width와 height값도 바뀐 것과 같은 결과를 얻는다.
Card.width, c1.width, c2.width는 모두 같은 저장공간을 참조하므로 항상 같은 값을 갖게 된다.
인스턴스 변수는 인스턴스가 생성될 때 마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 갖는다.
[플래시동영상]자료실의 플래시동영상 MemberVar.swf을 꼭 보도록하자.



3.9 클래스메서드(static메서드)와 인스턴스메서드


변수에서 그랬던 것과 같이, 메서드 앞에 static이 붙어 있으면 클래스메서드이고 붙어 있지 않으면 인스턴스메서드이다.
클래스 메서드는 호출방법 역시 클래스변수처럼, 객체를 생성하지 않고도 '클래스이름.메서드이름(매개변수)'와 같은 식으로 호출이 가능하다.
그렇다면 어느 경우에 static을 사용해서 클래스메서드로 정의해야하는 것일까?

클래스는 '데이터(변수)와 데이터에 관련된 메서드의 집합'이라고 할 수 있다. 같은 클래스 내에 있는 메서드와 멤버변수는 아주 밀접한 관계가 있다. 인스턴스메서드는 인스턴스변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는데 인스턴스변수를 필요로 하는 메서드이다.
그래서 인스턴스변수와 관계없거나(메서드 내에서 인스턴스변수를 사용하지 않거나), 클래스변수만을 사용하는 메서드들은 클래스메서드로 정의한다.

물론 인스턴스변수를 사용하지 않는다고 해서 반드시 클래스 메서드로 정의해야하는 것은 아니지만, 그렇게 하는 것이 일반적이다.
참고로 Math클래스의 모든 메서드는 클래스메서드임을 알 수 있다. Math클래스에는 인스턴스변수가 하나도 없거니와 Math클래스의 함수들은 작업을 수행하는데 필요한 값들을 모두 매개변수로 받아서 처리 하기 때문이다. 이처럼, 단순히 함수들만의 집합인 경우에는 클래스메서드로 선언한다.

[참고]인스턴스 변수 뿐만 아니라 인스턴스 메서드를 호출하는 경우에도 인스턴스 메서드로 선언되어야 한다. 인스턴스 메서드를 호출하는 것 역시 인스턴스 변수를 간접적으로 사용하는 것이기 때문이다.

[예제6-12] MyMathTest2.java

class MyMath2 {
      long a, b;
     
      // 인스턴스변수 a, b를 이용한 작업을 하므로 매개변수가 필요없다.
      long add() {       return a + b; }
      long subtract() {       return a - b; }
      long multiply() {       return a * b; }
      double divide() {       return a / b; }

      // 인스턴스변수와 관계없이 매개변수만으로 작업이 가능하다.
      static long add(long a, long b) {       return a + b; }
      static long subtract(long a, long b) {       return a - b; }
      static long multiply(long a, long b) {       return a * b; }
      static double divide(double a, double b) {       return a / b; }
}

class MyMathTest2 {
      public static void main(String args[]) {
            // 클래스메서드 호출
            System.out.println(MyMath2.add(200L, 100L));
            System.out.println(MyMath2.subtract(200L, 100L));
            System.out.println(MyMath2.multiply(200L, 100L));
            System.out.println(MyMath2.divide(200.0, 100.0));

            MyMath2 mm = new MyMath2();
            mm.a = 200L;
            mm.b = 100L;
            // 인스턴스메서드는 객체생성 후에만 호출이 가능함.
            System.out.println(mm.add());
            System.out.println(mm.subtract());
            System.out.println(mm.multiply());
            System.out.println(mm.divide());

}
[실행결과]
300
100
20000
2.0
300
100
20000
2.0

인스턴스메서드인 add(), subtract(), multiply(), divide()는 인스턴스변수인 a와 b만으로도 충분히 원하는 작업이 가능하기 때문에, 매개변수를 필요로 하지 않으므로 괄호()에 매개변수를 선언하지 않았다.
반면에 add(long a, long b), subtract(long a, long b) 등은 인스턴스변수 없이 매개변수만으로 작업을 수행하기 때문에 static을 붙여서 클래스메서드로 선언하였다. MyMathTest2의 main메서드에서 보면, 클래스메서드는 객체생성없이 바로 호출이 가능했고, 인스턴스메서드는 MyMath2클래스의 인스턴스를 생성한 후에야 호출이 가능했다.
이 예제를 통해서 어떤 경우 인스턴스메서드로, 또는 클래스메서드로 선언해야하는지, 그리고 그 차이를 이해하는 것은 매우 중요하다.



3.10 클래스멤버와 인스턴스멤버간의 참조와 호출.


같은 클래스에 속한 멤버들간에는 별도의 인스턴스를 생성하지 않고도 서로 참조 또는 호출이 가능하다. 단, 클래스멤버가 인스턴스멤버를 참조 또는 호출하고자 하는 경우에는 인스턴스를 생성해야 한다.
그 이유는 인스턴스멤버가 존재하는 시점에 클래스멤버는 항상 존재하지만, 클래스멤버가 존재하는 시점에 인스턴스멤버가 항상 존재한다는 것을 보장할 수 없기 때문이다.

[예제6-] ArrayEx.java

class MemberCall {
      int iv = 10;
      static int cv = 20;

      int iv2 = cv;
//   static int cv2 = iv;                   에러. 클래스변수는 인스턴스 변수를 사용할 수 없음.
      static int cv2 = new MemberCall().iv;   // 굳이 사용하려면 이처럼 객체를 생성해야함.

      static void classMethod1() {
            System.out.println(cv);
//         System.out.println(iv);       에러. 클래스메서드에서 인스턴스변수를 바로 사용할 수 없음.
            MemberCall c = new MemberCall();      
            System.out.println(c.iv);   // 객체를 생성한 후에야 인스턴스변수의 참조가 가능함.
     }

      void instanceMethod1() {
            System.out.println(cv);            
            System.out.println(iv);  // 인스턴스메서드에서는 인스턴스변수를 바로 사용가능.
     }

      static void classMethod2() {
            classMethod1();
//         instanceMethod1(); 에러. 클래스메서드에서는 인스턴스메서드를 바로 호출할 수 없음.
            MemberCall c = new MemberCall();
            c.instanceMethod1(); // 인스턴스를 생성한 후에야 인스턴스메서드를 호출할 수 있음.
      }
     
      void instanceMethod2() { // 인스턴스메서드에서는 인스턴스메서드와 클래스메서드
            classMethod1();         // 모두 인스턴스생성없이 바로 호출이 가능하다.
            instanceMethod1();
     }
}

클래스멤버(클래스변수와 클래스메서드)는 언제나 참조 또는 호출이 가능하다.
그렇기 때문에 인스턴스멤버가 클래스멤버를 참조, 호출하는 것은 아무런 문제가 안 된다.
클래스멤버간의 참조 또는 호출 역시 아무런 문제가 없다.

그러나, 인스턴스멤버(인스턴스변수와 인스턴스메서드)는 반드시 객체를 생성한 후에만 참조 또는 호출이 가능하기 때문에 클래스멤버가 인스턴스멤버를 참조, 호출하기 위해서는 객체를 생성하여야 한다.

하지만, 인스턴스멤버간의 호출에는 아무런 문제가 없다. 하나의 인스턴스멤버가 존재한다는 것은 인스턴스가 이미 생성되어있다는 것을 의미하며, 즉 다른 인스턴스멤버들도 모두 존재하기 때문이다.

실제로는 같은 클래스 내에서 클래스멤버가 인스턴스멤버를 참조 또는 호출해야하는 경우는 드물다. 만일 그런 경우가 발생한다면, 인스턴스메서드로 작성해야할 메서드를 클래스메서드로 한 것은 아닌지 한번 더 생각해봐야 한다.

[알아두면 좋아요]

수학에서의 대입법처럼, c = new MemberCall()이므로 c.instanceMethod1();에서 c대신 new MemberCall()을 대입하여 사용할 수 있다.

      MemberCall c = new MemberCall();
      int result = c.instanceMethod1();

위의 두 줄을 다음과 같이 한 줄로 할 수 있다.

      int result = new MemberCall().instanceMethod1();

대신 참조변수를 사용하지 않았기 때문에 생성된 MemeberCall인스턴스는 더 이상 사용할 수 없다

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/16 11:27

▩ 자바 프로그램의 구조

/*
public
- 외부에서 별다른 제약없이 이 클래스에 접근 할 수 있습니다.
- private, protected, friendly

class
- 현재 만들어지는 모듈은 클래스입니다.
- interface
 
Hello
- 클래스 이름, 파일명은 Hello.java로 대소문자도 일치해야합니다.
*/
public class Hello {

/*   
public: 외부에서 이 메소드는 아무런 제약없이 호출할 수 있습니다.
static: 객체를 생성하지 않고도 메모리할당이 이루어져
        사용할 수 있습니다.
void  : 이 메소드는 호출된후 처리결과를 리턴하지 않습니다.
        int, float, String등 각 타입이 가능 
main  : JVM에 의해서 최초로 자동으로 호출되는 메소드입니다.
        반드시 한개만 존재해야 합니다.
String[]: 문자열을 저장할 수 있는 배열을 의미합니다. 1차원 배열
args  : 배열명입니다. 도스상에서 입력한 인수를 가져옵니다.
*/
    public static void main(String[] args) {
//System.out.println("AAA"): 화면에 AAA문자열을 출력합니다.
//    문자열은 반드시 Double Quotation Mark로 감싸주어야 합니다.
//System.out.println(10): 화면에 숫자 10이 출력합니다.
//";"은 명령의 종결을 표시합니다.
        System.out.println("안녕하세요.!!!");
        System.out.println(10);
    } //중괄호, 중괄호는 열린 갯수만큼 닫혀야합니다.
}
//중괄호안에 들어가는 코드는 일반적으로 4자정도의 들여쓰기를
//합니다.


// 단일행 주석

/*
  여러행 주석1
  여러행 주석2
 */
 
/**
 * Documentation 주석
 */



  
 

▩ 식별자
   - 클래스, 메소드, 변수 이름
   - 이름 자체로 어느정도 내용이 식별이 되어야 합니다.

1. 클래스 이름
   - 첫자는 대문자가 아니어도 에러는 발생이 안되나 일반적으로 첫자는 대문자를 이용합니다.
     또한 마디마다 대문자를 이용합니다.

     Hello, HelloWorld, CompanyName, Company_name

   - 스칼라 기법을 이용합니다.



 

2. 메소드명
   - 첫자는 일반적으로 소문자로 시작합니다.
   - 메소드의 마디는 대문자를 이용합니다.

     println(), printName(), print_name()




3. 변수의 작성 규칙
   - int kuk = 10; 이라고 선언 했을 경우 kuk는 변수가 됩니다. 또한 식별자로 포함이 됩니다.
   - String name="왕눈이"; 이런 경우는 객체변수에 해당이 됩니다.
   - 알파벳, 대소문자, 숫자, _, $만 이용
   - 첫 문자가 숫자이면 안됨
   - 대소문자 완벽히 구별(파일명, 폴더 모두 해당)
   - 키워드(예약어)와 같으면 안됨
   - 길이 제한 없음(변수, 메소드명은 5자 ~ 15자  안팎)
   - 이름만 보고 알아 볼수 있도록 의미 부여
   - 스칼라 표기법: 무조건 단어의 첫자를 대문자를 사용합니다.
   - 헝가리안 표기법: 단어의 약자를 추출하여 이용합니다.  CompanyName --> CN
  
   예) 권장되는 변수명 : companyName, i_kuk, jumsu_kuk, jumsu_eng, jumsu = _jumsu
    




▩ 데이터 형
   - CPU와 메모리의 한계 때문에 데이터타입은 정확하게 지정해야 합니다.

1. 논리형
   - boolean: 1 Byte(8 Bit)
   - 초기값 : false
   - 갖을 수 있는 값의 범위:true, false
   - 조건문에서 조건이 참/거짓인지 판별하는 기준으로 쓰입니다.
  
     boolean bo=true;




2. 문자형
   - char: 2 Byte(16 Bit)
   - 초기값 : \u0000
   - 범위: \u0000 ~ \uFFFF(Unicode 0~65535)
 
     char grade = 'A';



3. 정수 숫자형(음의 정수, 양의 정수)

※ 2진수의 원리

  

※ 음수의 원리(반도체에서의 양수/음수의 원리)
   - 1의 보수
   - 부호화 절대치
   - 2의 보수


   - byte: 1 Byte
   - 초기값: 0
   - 값의 범위: -128 ~ 127, -2^7 ~ 2^7-1

   1 Byte: 8Bit

   1 Bit: 2가지 표현, 0, 1
   2 Bit: 4가지 표현, (0,0), (0,1), (1,0), (1,1)
   3 Bit: 8가지 표현, (0,0), (0,1), (1,0), (1,1) ...
   4 Bit: 16가지 표현, (0,0), (0,1), (1,0), (1,1) ...
   5 Bit: 32가지 표현, (0,0), (0,1), (1,0), (1,1) ...
   6 Bit: 64가지 표현, (0,0), (0,1), (1,0), (1,1) ...
   7 Bit: 128가지 표현, (0,0), (0,1), (1,0), (1,1) ...
   8 Bit: 256가지 표현, (0,0), (0,1), (1,0), (1,1) ...

   256b ---> 128 ~ 128 ---> -128 ~ +128 ---> -128 ~ +127
  

>>>>> ByteTest.java
/*
 * byte는 8bit
 * -128 ~ +127
 * */

public class ByteTest {

    public static void main(String[] args) {
        byte b = 127;
        //byte b1 = 128; //ERROR
        byte b2 = -128;
        //byte b3 = -129;
       
        System.out.println(b);
        System.out.println(b2);
    }
}




   - short: 2 Byte
   - 초기값: 0
   - 값의 범위: -32768 ~ 32767, -2^15 ~ 2^15-1
  


   - int: 4 Byte
   - 초기값: 0
   - 값의 범위: -2147483648 ~ +2147483647, -2^31 ~ 2^31-1


   - long: 8 Byte
   - 초기값: 0
   - 값의 범위: -2^61 ~ 2^61-1




4. 실수 숫자형
   - float: 4 Byte
   - 초기값: 0.0
   - -1.40e-45 ~ +3.40e+38

   - double: 8 Byte
   - 초기값: 0.0
   - 값의 범위: -4.94e-324 ~ 1.79e+308


>>>>> Silsu.java
public class Silsu {

 public static void main(String[] args) {
      //실수는 기본적으로 double로 인식됩니다.
      //float f = 10.5;
        float f = 10.5f;
        System.out.println("실수 출력:"+f);
       
        double d = 10.5;
        System.out.println("더블형 실수 출력:"+d);
 }
}



▶ 변수, 상수 실습
   - System.out.println()메소드는 기본적으로 10진수로 출력합니다.
   - 출력의 연결은 '+'기호를 사용합니다.

>>>>> Integer_Test.java
public class Integer_Test {
       public static void main(String args[]) {
          System.out.println("정수형 상수 예제");
          System.out.println("10진수 26 10진수로: " + 26);
          System.out.println("8진수 26 10진수로: " + 026);    //숫자0은 8진수
          System.out.println("16진수 AB는 10진수로: " + 0xAB);  //0x 16진수
       }
}




>>>>> Float_Test.java
public class Float_Test {
   public static void main(String args[]) {
      System.out.println("실수형 상수 예제");
      System.out.println("양 실수 12.345: " + 12.345);
      System.out.println("음 실수 -12.345: " + -12.345);
     
      //12.34E3 == 12.34E+3 == 12.34 * 1000
      System.out.println("지수 표현 12.34E3: " + 12.34E3);

      //12.34E-3 == 12.34E-3 == 12.34 / 1000
      System.out.println("지수 표현 12.34E-3: " + 12.34E-3);
   }
}




>>>>> String_Test.java
public class String_Test {
   public static void main(String args[]) {
      String str1 = "My Name is ";
      String str2 = "강";
      String str3 = "남";
      String str4 = "it";

      System.out.println("문자열형 상수 예제");
      System.out.println("-------------------------");
      System.out.println(str1 + str2 + str3 + str4 + 100 + 200);
   }
}




>>>>> Variable_Test.java
public class Variable_Test {
   public static void main(String args[]) {
      int i = 1234;
      int j = 5678;
      int hap = 0;

      hap = i + j;
     
      //200 = i + j;
     
      System.out.println("변수를 이용한 예제");
      System.out.println("i = " + i);
      System.out.println("j = " + j);
      System.out.println("hap = :" + hap);
     
     
      /*
      CPU                  Stack
     
      ALU <----┬---- int i=1234; <-┐
                     └---- int j=5678;    │
                                                 │
      i+j --------------------------┘
                                     6912       
                    
      */

      i = i + j;
      System.out.println("i = i + j => " + i);
   }
}





▩ 형변환
   - 작은 타입의 데이터형은 큰 타입의 데이터형으로 아무런 작업 없이 변환할 수 있습니다.
   - 큰 타입의 데이터형을 작은 타입의 데이터형으로 변환할시에는 캐스트 연산자를 써서 형변환을

      해야합니다.
   - Casting시에는 데이터 짤림이 발생하는지 확인해야 합니다. 데이터 짤림이 발생하면 캐스팅은

      피해야 합니다.
   - 실수를 정수로 바꾸는 경우에 주로 사용합니다.

>>>>> Cast_Test.java
public class Cast_Test {
       public static void main(String args[]) {
          int i = 1234;
          int k;
          float f = 10.5f;
          double d = 100.55;
         
          // k = f;  k는 정수만 저장함으로 ERROR
          k = (int)f;  //작은 타입 = (작은 타입)큰타입
          System.out.println(k); //10
         
          f = i;  //실수형 = 정수형 f = 1234
         
          System.out.println(f); //1234.0
         
          f = (float)d;
          System.out.println(f); //100.55         
       }
    }




public class Cast_Test2 {
    public static void main(String[] args) {
                        //MSB             LSB
                        //3       2       1
                        //18765432187654321
                        //----------------- 
        byte  b = 100;  //         01100100 8비트 필요
        short s = 300;  // 0000000100101100 16비트로 필요
        int   i = 70000;//10001000101110000 24비트가 필요
       
        //                         32+8+4=44
        b = (byte)s;    //00000001/00101100
        System.out.println("b=" + b);

    }

}




▩ 연산자
   
1. 산술(수치) 연산자 : +, -, *, /, %
   - 정수/정수 = 정수
   - float n = 0.0f; f를 제거하면 double 8바이트가 됩니다.

>>>>> Arithmetic.java
public class Arithmetic {
   public static void main(String args[]) {
      int i = 20;
      int j = 12;

      int a = i + j;
      int b = i - j;
      int c = i * j;
      int d = i / j;
      int e = i % j;
      float n = 0.0f;

      System.out.println("i : " + i + "j : " + j);
      System.out.println("덧셈 결과 : " + a);
      System.out.println("뺄셈 결과 : " + b);
      System.out.println("곱셈 결과 : " + c);
      System.out.println("나눗셈 결과 : " + d);
      System.out.println("나머지 결과 : " + e);
     
      n = i/j;
      System.out.println("정수/정수의 결과:" + n);
   }
}




2. 대입 연산자 : =
   - 좌변은 상수값이 아니라 기억장소가 와야합니다.
     a = i + j;
     b = 10 + 20;
     100 = i + 10;



3. 연산후대입 연산자 : +=, -=, *=, /=, %=
   - 처리속도 향상

>>>>> Proportion.java
public class Proportion {
   public static void main(String args[]) {
      int i = 12;
      int j = 27;

      System.out.println("i : " + i + ", j : " + j);
      System.out.println("---------------");

      i += j; //i=i + j;
      System.out.println("i+=j : " + i);

      i -= j; //i=i - j;
      System.out.println("i-=j : " + i);

      i *= j; //i=i * j;
      System.out.println("i*=j : " + i);

      i /= j; //i=i / j;
      System.out.println("i/=j : " + i);

      i%=j; //i=i % j;
      System.out.println("i%=j : " + i);
   }
}




4. 증가/감소 연산자 : ++, --
   - 알아보기 쉽게 코딩하는 것이 필요합니다.

>>>>> IncDec.java
public class IncDec{
      public static void main(String args[]){
          int x=1;
          int y = x++; //후위 연산자  
          // y = x;
          // x = x + 1;

          System.out.println("x의 값은" + x); //2
          System.out.println("y의 값은" + y); //1
       
          x=1;           
          int z=++x; //전위 연산자
          //x = x + 1;
          //z = x;     
       
         System.out.println("x의 값은" + x); //2
         System.out.println("z의 값은" + z); //2
        
         x=1;
         x++; //++x;
         z=x;
         System.out.println("-----------------------");         
         System.out.println("x의 값은" + x); //2
         System.out.println("z의 값은" + z); //2
        
      }
}




>>>>> IncDec2.java
public class IncDec2{
      public static void main(String args[]){
          int x=1;
          int y = x--; //후위 연산자  
          // y = x;
          // x = x + 1;

          System.out.println("x의 값은" + x); //2
          System.out.println("y의 값은" + y); //1
       
          x=1;           
          int z=--x; //전위 연산자
          //x = x + 1;
          //z = x;     
       
         System.out.println("x의 값은" + x); //2
         System.out.println("z의 값은" + z); //2
        
      }
}




5. 관계(비교) 연산자 : <, <=, >=, >, ==, !=, instanceof

>>>>> Compare.java
public class Compare {
   public static void main(String args[]) {
      int i = 12;
      int j = 23;
      int k = 17;
      String name="왕눈이";

      System.out.println("변수 i는 " + i + ", 변수 j는 " + j + ", 변수 k는" + k + "이다.");
      System.out.println("-------------------");
      System.out.println("12==23 : " + (i==j));
      System.out.println("12!=17 : " + (i!=k));
      System.out.println("23<17  : " + (j<k));
      System.out.println("k>i : " + (k>i));
      System.out.println("i<=k : " + (i<=k));
      System.out.println("i>=j : " + (i>=j));
     
      System.out.println(name instanceof String);
    //System.out.println(i instanceof int);     
   }
}




6. 비트연산자
   - byte 0 ~ 255까지 출력하기

>>>>> Bitwise.java
//>>> 무조건 0이 채워지는 shift연산만 이루어짐
class Bitwise {
      public static void main(String args[]) {
        int a = 2;
        int b = 5;
       
        int c = a | b; //or
        //2진수 연산
     
        // ....8421 
        // 00000010
        //+00000101
        //--------- 
        // 00000111--> 7
       
        int d = a & b; //and
        // 00000010
        //+00000101
        //--------- 
        // 00000000--> 0
       
       
        int e = a ^ b; //Exclusive or
        // 00000010
        //+00000101
        //--------- 
        // 00000111--> 7
       
       
        int i; int j;
        i = a << 2;    //좌 shift 연산
        // ....8421 
        // 00000010
        // 00001000 --> 8
       
       
        j = b >> 2;    //우 shift 연산
        // ....8421 
        // 00000101
        // 00000001 --> 1
       

        System.out.println("        a = " + a);
        System.out.println("        b = " + b);
        System.out.println("      a|b = " + c);
        System.out.println("      a&b = " + d);
        System.out.println("      a^b = " + e);
        System.out.println("     a<<2 = " + i);
        System.out.println("     b>>2 = " + j);
      }
    }




7. 논리연산자(조건 연산자)
   - 조건문과 함께 많이 사용됨
   - &&: 양쪽의 조건이 전부 맞아야 참입니다.
   - ||: 어느 한쪽만 참이면 참입니다.




8. 삼항 연산자

>>>>> Ternary.java
class Ternary
{
    public static void main(String args[])
    {
        int x = 10;
        int y;
       
        //System.out.println("결과는 " + y);

        //System.out.println("초기화되지 않은 y의 값: " + y);
        //y = 조건문 ? 참값 : 거짓값
        y = x < 9 ? 3 : 5;
       System.out.println("결과는 " + y);
    }
}

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/05 17:52

출처 : http://cafe.naver.com/javalicense.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=123


번 호 1  
ERROR Exception in thread "main" java.lang.NoClassDefFoundError: 파일명
발생되는 경우 클래스 파일을 찾을 수 없는 경우
조 언 실행하려는 클래스 파일 이름이 제대로 되어 있는지 확인한다.
또한, CLASSPATH 설정이 제대로 되어 있는지 확인하며 (도스모드에서 set명령어)
만약, 되어있지 않다면 설정한다. (CLASSPATH = jdk1.3/jre/lib/rt.jar; 2-1강좌 참조)
 
번 호 2  
ERROR cannot resolve symbol
symbol : class in(에러가 난 부분)
location : class StackTest(찾으려는 위치)
발생되는 경우 이해할 수 없는 클래스나 메소드, 변수명이 올경우
조 언 보통 이 에러는 철자가 틀렸을 경우에 많이 발생한다. 클래스, 메소드, 변수의 철자를 세심히 확인해 본다.
특히, 철자를 확인할때 대소문자 구분을 확실히 체크한다.(자바는 대소문자를 구별한다.) 그리고 클래스에서 발생할 경우 import를 해주었는지 확인해 봅니다.
 
번 호 3  
ERROR non-static variable 변수이름(or method 메소드이름) cannot br referenced from a static context
발생되는 경우 static 메소드 안에서 static 으로 선언되지 않은 메소드나 변수를 참조(사용)했을 경우.
특히, 메소드의 경우는 인스턴스를 사용하지 않고 static메소드 내에서 바로 선언한 경우.
조 언 static 선언자의 사용여부를 살펴보고 static 메소드 안에 static으로 선언되어지지 않은 메소드나 변수가 있느지 확인해본다.
만약 그런것이 있으면 메소드를 새로 만들어 그쪽에서 선언한다. 단, 인스턴스를 생성해서 불러줘야 한다는 것을 잊지 말아야한다.
 
번 호 4  
ERROR valiable 변수명 might not have been initialized
발생되는 경우 지역변수인 변수명의 변수가 초기화가 되어있지 않았을 경우
조 언 지역변수(메소드 내에서 선언한 변수)를 초기화 하지 않은채 선언했을 경우 발생한다.
멤버 필드가 아닌 경우는 반드시 변수 선언시 초기화를 해주어야 한다.
(멤버 필드는 자바 프로그램 자체에서 자동으로 default값으로 초기화 해준다.)
 
번 호 5  
ERROR class 클래스명 is public, should be declared in a file named 클래스명.java
발생되는 경우 클래스명이 public으로 선언되었는데 파일명과 다를 경우
조 언 public으로 선언된 클래스가 있다면 반드시 그 클래스명과 파일명이 같아야 한다.
클래스명과 파일명의 대소문자 및 철자가 같은지 비교해 본다.
또한, public으로 선언된 클래스가 하나 이상 있는지 찾아본다.(반드시 하나만 있어야한다.)
 
번 호 6  
ERROR push(java.lang.object)[메소드(인자로 받을 수 있는 형)] in java.util.Stack(메소드의 클래스) cannot be applied to (int)[잘못 들어간 형]
발생되는 경우 메소드에서 인자를 받을 때 받을 수 있는 형이 아닌 자료형 또는 클래스형을 사용할 경우
조 언 사용하는 메소드의 API를 참고하여 어떤 형을 인자로 받을 수 있는지 찾아본다.
API를 보지 못할 경우는 각 자료형으로 인자를 직접 바꾸어 본다.
 
번 호 7  
ERROR java.lang.NoSuchMethodError: main
Exception in thread "main"
발생되는 경우 클래스 파일 안에서 main() 메소드를 찾을 수 없는 경우
조 언 자바 애플릿이 아닌 이상 자바 애플리케이션은 반드시 main() 메소드를 사용해야 합니다.
main() 메소드를 빼먹지 않았는지 확인해 보십시요. 또한 public static void main(String[] args) 형식으로 씌어졌는지도 확인해 보십시요.
(main 클래스는 반드시 위와 같은 형식으로 만들어져야 합니다.)
 
번 호 8  
ERROR unreported exception java.io.IOException(Exception명); must be caught or declared to be thrown
발생되는 경우 예외가 발생하는데 예외처리를 해주지 않았을 경우
조 언 예외를 발생하는 메소드 같은 경우는 반드시 예외처리를 해주어야 합니다.
예외를 발생하거나 예외처리를 해야하는 메소드는 API를 확인해 보시면 알 수 있습니다.
그렇지 않다면 컴파일 후 지금처럼 에러가 난 예외를 예외처리해 주시면 됩니다.
또한, 예외를 처리할 때는 메소드 차원에서 throws 예외명을 이용해서 처리할 수 있고
try{} catch{} 구문을 이용해서 직접 처리해 주셔도 됩니다.(예외 강좌를 참고하세요.)
특히, 예외도 클래스이므로 반드시 예외가 들어간 패키지를 import 해주어야 합니다.
 
번 호 9  
ERROR Note : Calculator.java(파일명) uses or overrides a deprecated API.
Note : Recompile with -deprecation for details.
발생되는 경우 JDK 버전이 높아졌거나 보안등의 기타이유로 사용이 deprecated된 메소드를 사용한 경우
조 언 이건 예외라기 보다는 경고 입니다.(실행하면 됩니다.^^)
JDK가 버전이 높아지거나 보안등의 이유에 따라 예전에 만들어졌지만 필요가 없어지거나 대체된 메소드가 생겨났습니다.
그런 메소드를 deprecated 되었다고 하는데 이것은 API상에 나왔있습니다.
또한, 컴파일할때 -deprecation 옵션주면 어떤 메소드가 deprecate됐는지 알수있읍니다.
사용이 중지 됐다고 보기 보다는 사용을 가능하면 하지 않게끔 해주는 거죠.
대치되었거나 버전 업된 메소드를 사용하시면 됩니다.
 
번 호 10  
ERROR MouseEvent(클래스명) should be declared abstract; it does not define mouseDragged(java.awt.event.MouseEvent)[메소드명(메소드가 포함된 클래스)] in MouseEvent(클래스명)
발생되는 경우 implements한 Interface의 모든 메소드를 구현하지 않아서 발생됨
조 언 Interface는 모든 메소드가 선언만 되고 구현되지 않은 추상(abstract) 메소드입니다.
만약 Interface를 implements하려면 implements한 클래스가 Interface에서 선언한 모든 메소드를 구현해 주어야 합니다.
하나라도 빠질 경우 implements한 클래스도 추상 클래스로 보고 에러가 발생합니다.
에러에 구현해 주어야할 메소드명이 나오므로 그곳에 쓰여있는 메소드를 구현해 주면 됩니다.
만약, 그 메소드를 구현해 주었는데 에러가 나면 철자 및 대소문자를 다시 확인해 보십시요.
 
번 호 11  
ERROR incompatible types
found : /null(입력한 자료형)
required : int(요구하는 자료형)
발생되는 경우 입력을 했을때 맞지 않는 자료형이나 클래스형을 입력할 경우
조 언 incompatible 은 '성미가 맞지 않는','모순된' 이라는 뜻을 가진 단어 입니다.
단어뜻 처럼 입력 경우 required 에 나타난 자료형 및 클래스형을 요구하는데
found 에서 나타난 자료형 및 클래스형을 써주어서 입력을 하지 못하게 되어서 발생하는 에러입니다.
found 에 나타난 자료형을 required 에 나타난 자료형으로 변경해 주시면 됩니다.
 
번 호 12  
ERROR package java.servlet(패키지명) does not exist
발생되는 경우 import한 패키지가 존재하지 않을 경우
조 언 import한 패키지가 존재하지 않을 경우에 발생하는 에러입니다.
철자와 대소문자를 먼저 확인하고 CLASSPATH 설정을 확인해 보시기 바랍니다.
또한 그 곳에 패키지가 jar파일로 있는지도 확인해 보셔야 합니다.
(API에 나와있는 패키지는 rt.jar에 다 있습니다.
단 javax가 붙거나 다름으로 시작되는 확장 패키지는 설치해 주어야합니다.(javax.swing 제외))
 
번 호 13  
ERROR java.lang.NullPointerException
Exception in thread "main"(메소드) java.lang.NullPointerException
at java.awt.Container.addImpl(Container.java:341)... [에러가 일어난 부분]
발생되는 경우 참조하거나 사용한 클래스 또는 자료형이 초기화 되지 않은 경우
조 언 보통 이것은 awt나 배열 부분에서 자주 발생하는데 초기화를 해주지 않아서 많이 발생합니다.
자바의 변수들은 기본적으로(자동으로 초기화 되는 멤버필드등을 제외하고) 초기화를 요구합니다.
에러에 체크된 부분을 검토해 보시고 초기화를 해주십시요.
 
번 호 14  
ERROR ';'(빠진 부분) expected
발생되는 경우 문법상으로 써야할 것을 쓰지 않은 경우 발생합니다.
조 언 주로 ';'을 안써주시거나 아님 '()'(괄호)를 열기만 하고 닫지 않은 실수를 할 경우 발생합니다.
대부분 이 에러가 발생한 경우는 에러에 나온것을 소스에 추가해 주시면 됩니다.
 
번 호 15  
ERROR unexpected type
required : value(요구하는 타입)
found : class(소스상 써준 타입)
발생되는 경우 써주어야 할 타입이 아닌 잘못된 타입을 써주었을 경우
조 언 unexpected type 에러를 해석하면 '기대하지 않은 타입'이란 뜻을 가지고 있습니다.
즉, 원하는 타입(required)이 아닌데 잘못된 타입(found)을 써준 경우 발생합니다.
에러 체크된 부분의 타입을 required 에서 나타난 타입으로 변경해 주시면 됩니다.
 
번 호 16  
ERROR java.lang.ArrayIndexOutOfBoundsException
at Test.main(Test.java:10)[클래스.메소드(파일명:에러난 위치)]
Exception in thread "main"(예외가 던져진 메소드)
발생되는 경우 배열의 범위를 넘어선 값을 넣었을 경우
조 언 위의 에러는 특이하게 컴파일은 이상없이 되지만 실행을 하면 발생하는 에러입니다.
배열의 범위를 넘어설 경우에 발생하므로 에러난 위치의 배열의 참조 범위를 확인해보시고
선언해둔 배열의 범위에 맞게 조정해 주시면 됩니다.
 
번 호 17  
ERROR illegal start of expression
발생되는 경우 선언자(modifier)를 잘못 집어 넣은 경우
조 언 에러의 단어뜻을 확인해 보면 '표현의 시작이 부적격 합니다.'하고 해석할 수 있습니다.
보통 선언자가 맞지 않거나 쓰일데가 아닌데 선언자를 줄 경우에 많이 발생합니다.
특히 메소드안에서 static 선언자를 쓴 경우에는 직격으로 볼수 있죠.
에러가 난 부분의 선언자를 제거하거나 맞는 것인지 다시 확인해 보십시요.
 
번 호 18  
ERROR java.io.InputStream(클래스) is abstract; cannot be instantiated
발생되는 경우 abstract로 선언된 클래스를 직접 new 명령어를 이용하여 인스턴스화 할 경우
조 언 abstract로 선언된 클래스를 직접 new 명령어를 이용하여 인스턴스화 할 경우에 발생하는 에러입니다.
왜냐하면, 추상 클래스는 직접 new 명령어를 이용하여 인스턴스화 할수 없기 때문입니다.(객체를 못만든다구요.)
이 경우에는 인스턴스를 다른 방법으로 생성하시면 됩니다.
예를 들어 인스턴스를 반환하는 메소드를 이용한다거나 상속을 통해서 상속받은 클래스의 인스턴스를 만들어
직접 인스턴스를 만드는 효과를 낼수도 있구요. 원하시는 방법으로 바꾸어 보시길...
 
번 호 19  
ERROR local variable name(변수명) is accessed from within inner class; needs to be declared final
발생되는 경우 Local Class의 변수를 final로 선언하지 않은 경우
조 언 Local Class의 변수는 참조변수의 참조값 변동을 방지하기 위하여 final 선언자를 붙여주어야 합니다.
변수에 final 선언자를 붙이면 변수는 값을 변동할 수 없는 상수 처럼 쓰이며
만약 이 값을 참조할 경우 자바는 이 값을 넘기는게 아니라 이 값의 복사본을 참조 값으로 넘기게 됩니다.
그러므로 Local Class에서 참조값 변동없이 변수를 참조할 수 있게 되는 것입니다.
Local Class를 정의해준 곳을 살펴보고 final 선언자를 확실하게 확인하시기 바랍니다.
 
번 호 20  
ERROR inner classes cannot have static declarations
발생되는 경우 내부 클래스 안에서 static 선언자를 쓴 경우
조 언 내부 클래스 안에서는 static 선언자를 쓸수 없습니다.
내부 클래스 안에서 사용된 static 선언자를 제거해 주십시요.
 
번 호 21  
ERROR referenceto List is ambiguous,both class java.util.List(클래스) in java.util(패키지)
and class java.awt.List(클래스) in java.awt(패키지) match
발생되는 경우 클래스 사용시 다른 패키지내에 동일이름의 클래스들이 있어서 참조가 모호할 경우
조 언 예시를 보면 아시겠지만 import 한 패키지중에 같은 이름을 사용하는 클래스를 클래스 이름만으로
생성함으로서 참조가 모호해질 경우 발생하는 에러입니다.
이와 같은 경우는 import를 하나 제거 하거나 아님 java.util.List 이런식으로
직접 그 클래스의 패키지를 같이 써줌으로서 모호성을 제거할수 있습니다.
 
번 호 22  
ERROR m()(메소드명) in B(클래스명) cannot override m()(메소드명) in A(클래스명);
attempting to use incompatiable return type
발생되는 경우 클래스를 상속받고서 메소드를 오버라이드 하고자할때 잘못한 경우
조 언 클래스를 상속받고서 메소드를 오버라이드 할 경우에는 지켜야 하는 규칙이 있습니다.
1. 메소드의 이름이 같아야 합니다.
2. 메소드의 파라미터 개수, 데이터형이 같아야 합니다.
3. 메소드의 리턴형이 같아야 합니다.
4. 상위 메소드와 동일하거나 더 구체적인 Exception을 발생시켜야 합니다.
5. 상위 메소드와 동일하거나 접근범위가 더 넣은 접근 제한자를 사용해야 합니다.

님의 메소드 오버라이드시 위 규칙을 잘 지켰는가를 다시 한번 확인해 보세요.
 
번 호 23  
ERROR getPathBetweenRows(int,int)(메소드) has protected access in javax.swing.jTree(클래스)
발생되는 경우 protected로 선언된 메소드를 상속 없이 직접 불러쓸 경우
조 언 protected로 선언되어 있는 메소드는 상속하거나 같은 package에 있을 때만 쓸 수 있습니다.
상속해서 다시 public 메소드로 값을 받던지 아니면
public 메소드 중에서 비슷한 기능을 하는 메소드가 있는지 찾아서 바꾸어주어야 합니다.
 
번 호 24  
ERROR invalid method declaration; return type required
발생되는 경우 리턴 타입을 쓰지 않아 메소드의 선언이 잘못된 경우
조 언 리턴 타입을 쓰지 않아 메소드의 선언이 잘못된 경우에 발생하는 에러이므로
에러가 발생한 메소드를 확인해보고 리턴 타입을 맞게 적어주어야 합니다.
 
번 호 25  
ERROR Error occurred during initialization of VM
java.lang.ExceptionInInitializerError
발생되는 경우 static으로 선언된 변수중 초기화가 안되어 있는 것이 있는 경우
조 언 static으로 선언된 변수중에 초기화가 안된게 있는 경우에 발생하는 에러이므로
에러가 발생한 변수를 확인해보고 알맞은 초기화를 시켜주거나 변수의 위치를
자동 초기화가 가능한 메소드 밖의 클래스 변수로서 사용하게 합니다.
 
번 호 26  
ERROR Error opening registry key 'Software\JavaSoft\Java Runtime Environment'
Error: could not find java.dll
Error: could not find Java 2 Runtime Environment
발생되는 경우 중복설치 등으로 인해 레지스트리 키값이 잘못되어 있는 경우
조 언 중복설치 등으로 인해 레지스트리 키값이 잘못되어 있는 경우에 발생하는 에러이므로
레지스트리 편집기를 열어서 HKEY_LOCAL_MACHINE -> SOFTWARE -> JavaSoft에
보시면 3개의 키가 있을 겁니다. 그중에서 첫번째 키인 Java 런타임 환경 을 마우스
오른쪽 버튼으로 클릭하여 Java Runtime Environment로 이름을 바꿔주시면 됩니다.
 
번 호 27  
ERROR Error Registry Key 'Sofrware\JavaSofrware\Java Runtime Environment\CurrentVerison'
has value '1.1',but '1.3' is requried.
Error: could not find java.dll
Error: could not find java 2 Runtime Enviroment.
발생되는 경우 중복설치 등으로 인해 레지스트리 키값의 자바 버전이 잘못되어 있는 경우
조 언 중복설치 등으로 인해 레지스트리 키값의 자바 버전이 잘못되어 있는 경우에 발생하는 에러이므로
레지스트리 편집기를 열어서 HKEY_LOCAL_MACHINE -> SOFTWARE -> JavaSoft -> Java Runtime Environment의 Current version의 값을 1.3으로 되어있는지 확인해 주시면 됩니다.
 
번 호 28  
ERROR java.lang.ClassNotFoundException: org.gjt.mm.mysql.Driver(드라이버명)
발생되는 경우 JDBC로 데이터 베이스에 연결하는 중 드라이버를 찾지 못할 경우
조 언 JDBC를 연결하는 중에 드라이버를 찾지 못할 경우에 발생하는 에러이므로
각 데이터 베이스에 맞는 드라이버가 제대로 다운로드 되었는지 확인해 보시고
드라이버의 위치가 클래스 패스에 잡혀 있는지 확인해주시면 됩니다.
 
번 호 29  
ERROR Method printIn(java.lang.String)(메소드명) not found in class java.io.PrintStream(클래스명)
발생되는 경우 자신이 사용한 클래스의 메소드가 맞지 않는(=없는)경우
조 언 자신이 사용한 클래스의 메소드가 맞지 않는(=없는) 경우에 발생하는 에러이므로
API를 통해서 사용하고자 하는 클래스와 메소드를 다시 한번 확인해 봅니다.
보통 이경우 메소드의 철자나 대소문자를 잘못 쓴 경우가 많으니 그점을 유심히 살표봅니다.
마지막으로 철자와 대소문자도 맞는다면 메소드의 인자의 객체형을 맞게 주었는지 확인해보면 됩니다.
 

 

 

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/05 17:48

자바에서 Random값을 구하는 방법으로는 크게 다음 두가지가 있다.

  1) java.lang.math.Random

  2) java.util.Random


이때 첫번째 방법은 seed값을 변환할 수 없기 때문에 고르게 분포하지 않는다.

그래서 seed값을 변환해 고른 난수추출을 할 수 있는 방법이 필요한데 이때,

두번째 방법을 사용한다. 아래의 예제는 아주 간단히 정규분포(Normal / Gaussian)에서

난수를 추출하는 방법을 보여주고 있다.

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

import java.util.Random;


public class RandomNumber {

    public static void main(String[] args) {
        Random rand = new Random(System.currentTimeMillis()); // seed값을 배정하여 생성
        System.out.println(Math.abs(rand.nextGaussian()));         // 난수값 출력

    }

}

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


아래의 예제는 다양한 범위에서 난수를 추출하는 방법을 보여주고 있다.

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

import java.util.Random;


public class RandomNumber {

    public static void main(String[] args) {
        Random rand = new Random(System.currentTimeMillis()); // seed값을 배정하여 생성
        System.out.println(Math.abs(rand.nextInt(10)));                //0~10사이의 난수값생성
        System.out.println(Math.abs(rand.nextInt(9)+1));               //1~10사이의 난수값생성
        System.out.println(Math.abs(rand.nextInt(990)+10));           //10-100사이의 난수값생성

    }

}

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

nextInt([숫자])를 사용할경우 0~[숫자]까지의 범위에서 난수가 추출되므로 예로 0~9까지 난수를

추출한후 1을 더해주면 1~10까지의 난수가 추출됨.



** 참고사항 : 컴퓨터상에서 난수추출과 Seed값 배정법(출처 : 네이버 지식검색 자료모음)


컴퓨터는 생각을 할 수 없습니다. 그래서 무작위로 수를 뽑는 것 역시 불가능합니다.
단, 엄청나게 긴 수열을 만들어 내어서 "난수"로 보이는 숫자를 만들어 낼 수 있는데
그것이 유사 난수(Pseudo random)이라고 합니다.
단, 이 수열의 집합은 Seed라는 지정번호에 좌우되는데(Seed가 같을 경우, random을

해도 같은 수열만 나온단 말이 되겠죠) Seed의 숫자에 따라서 생성되는 수열이 달라집니다.

프로그래머들은 Seed 번호를 대개 현재의 시각에 대응시킵니다. 그래서 한번의 Random

호출시마다 다른 난수가 생성됩니다. 즉 명령을 실행하라고 인간이 엔터키나 클릭을 한

시점의 시간을 1000분의 1초를 단위로 추출해서 그 수를 기본으로 난수를 만들기 때문에

언제나 실행 할때마다 전혀 다른 난수가 나오게 되는것입니다.


최종적으로는, seed를 and or xor 등등을 여러번 섞고 왼쪽 오른쪽으로 돌렸다가 비트단위로

반정도로 잘라서 뒤섞고 하는방식으로 만듭니다.

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/05 17:45

클래스는 선언위치에 따라 다음과 같이 나뉘어 진다.

1. 일반 클래스

    1) 선언위치 : 파일의 시작부분

    2) 용      도 : 일반 클래스의 생성

    3) 특      징 : 일반적인 형태의 클래스

    4) 파일형태 : A.class

    5) 모      양 : class [클래스 이름]{

                       }


2. 중첩 클래스

    1) 선언위치 : 클래스의 내부

    2) 용      도 : 클래스와 연관관계가 밀접한 경우

    3) 특      징 : static 선언만 가능

    4) 파일형태 : A$B.class

    5) 모      양 : class [일반클래스 이름]{

                               static class [중첩클래스 이름]{

                               }

                        }


3. 내부 클래스

    1) 선언위치 : 클래스의 내부

    2) 용      도 : 이벤트 처리, 데이터 구조선언

    3) 특      징 : static 메소드 혹은 변수를 가질 수 없음

    4) 파일형태 : A$B.class

    5) 모      양 : class [일반클래스 이름]{

                               static class [내부클래스 이름]{

                               }

                        }


4. 지역 클래스

    1) 선언위치 : 메소드 내부

    2) 용      도 : 메소드 내에서만 사용되는 클래스를 생성할때

    3) 특      징 : 지역변수를 final로 생성

    4) 파일형태 : A$x$B.class

    5) 모      양 : class [일반클래스 이름]{

                               메소드{

                                      static class [지역클래스 이름]{

                                       }

                               }

                        }


5. 익명 클래스

    1) 선언위치 : 메소드 내부

    2) 용      도 : 단 한번만 정의하여 사용할때

    3) 특      징 : 지역클래스와 같으나 클래스 선언 후에 ; 붙임

    4) 파일형태 : A$x.class

    5) 모      양 : class [일반클래스 이름]{

                               메소드{

                                       new class [익명클래스 이름](){

                                       }

                               }

                        }

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/05 17:44

int[] arr = new int[2];

int arr[] = new int[2];    -> 많이씀.

int[] arr = { 0, 1 };

int arr[] = { 0, 1};


배열 선언은 이런 식으로 하게 됩니다.

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/10/01 12:28

자바가 가지는 특징 및 다른 언어와의 개발환경에 있어서의 차이점에 대해서 설명하세요.

특징

1. C++에 가깝지만 훨씬 간편하며 친숙한 언어입니다.

- 단순성이라는 설계 목표에 따라 고급언어들에 들어있는 여러 가지 복잡한 기능을 제거 했습니다.

* 복잡한 동기화 요소 통합, 간단한 구문, 풍부한 라이브러리 클래스를 통한 편리한 프로그래밍등

- 자바에는 포인터의 개념이 없습니다.

* 유효하지 않는 메모리 참조를 막아 안전성을 높이기 위해 포인터 기능을 제거했습니다.

- 자바는 쓰레기 수집이란걸 통해서 자동적으로 메모리를 관리 하고 있습니다.

* 쓰레기 수집이 없다면 프로그래머가 사용하지 않는 메모리를 체크하고 반환하는 일을 수동적으로

처리해야할것이다. 비효율적인면도 있지만, 프로그래머가 보다 프로그래밍에 집중할 수 있도록

도와줍니다.

- 컴파일된후 나온 파일이 다르다. 자바는 컴파일 하게 되면 바이너리 파일로 되어 있습니다.

2. 객체지향 언어입니다.

- 프로그램을 기술할 때, 단계보다는 데이터와 데이터를 가공하는 함수들에 초점을 갖춘언어입니다.

- 상속, 캡슐화, 다형성이 잘 적용된 순수한 객체 지향언어입니다.

- 모든 기능을 클래스화 해서 분리 작업이 가능하기 때문에 협업에 효율적이고 재사용이 유리합니다.

- 협업이 가능해 개발 시간이 줄어듭니다.

3. 플랫폼에 독립적입니다.

- 다양한 네트워크환경 및 하드웨어에서 사용 가능하도록 개발되어있습니다.

* HTTP등과 같은 TCP/IP네트워크 환경에서 동작하는 많은 프로토콜을 지원하는 라이브러리를

가지고 있습니다.

- 플랫폼에 독립적인 바이트코드를 이용하여 자바 가상 기계를 통한 인터프리터 방식으로 실행합니다.

4. 견고하고 보안에 강합니다.

- 인터넷과 대규모 분산환경을 염두해 풍부하고 다양한 네트워크 프로그래밍 라이브러를 통해 보다 짧은 시간에 쉽게 네트워크 관련 프로그램을 개발할수 있지만 다른 언어보다 안정성에 대한 중요성이 요구됩니다.

* Java코드는 바이러스,파일의 삭제나 수정,데이타 파괴 작업이나 컴퓨터 오류 연산등을 방지할 수

있는 환경에서 실행되도록 설계되었습니다.

* virus-free혹은 tamper-free시스템들의구축을 가능케합니다. 인증기술등은 공중키암호화에 기반을

두고 있습니다.

- 컴파일 할때, 유형 검사를 하여 에러를 막을 뿐만 아니라 도구들까지 명확한 유형 선언을 하도록 합니다..

- 포인터 연산을 지원하지 않음으로써 잘못된 주소를 가르킬 가능성을 없앴습니다.

- 모든 메모리 접근을 Java 시스템이 관리하고 제한하며 또한 예외 처리를 하여 시스템 붕괴의 우려가 없습니다.

* 메모리를 덮어 쓰거나 데이터를 망가뜨리는 가능성을 제거했습니다.

- 반복적인 형 검사를 통해서 프로그램의 신뢰성을 향상시킵니다.

5. 동적이고 멀티 스레드를 지원합니다.

- 시스템과는 관계없이 멀티스레드 구현이 가능합니다.

- 라이브러리 갱신의 경우 재컴파일이 불필요합니다.

 

개발환경

기계 중립적이며, 이식성이 뛰어나다는게 다른 다른언어와 구별되는 개발환경 차이점입니다.

- Web의 서버-클라이언트 환경에서 이기종 서버-클라이언트의 지원은 매우 중요한 문제입니다. 일반적으로 네트웍은 다양한 CPU와 OS를 가진 시스템들로 구성되어 있습니다. Java 응용 프로그램이 네트웍상의 어디에서든지 수행이 되기 위해서는 컴파일러가 기계 구조에 중립적인 오브젝트 파일 포맷을 생성해야 합니다. 그러므로, 실행 파일이 기계 중립적인 이진 코드입니다. 이 클래스 파일을 기계 종속적인 Java 런타임이 인터프리트하여 실행시키게 됩니다.

- 유형 정의를 시스템에 무관하게 정의하고 있습니다.

* 네트웍을 통해 프로그램을 다운받아 하드웨어 에 관계없이 사용하기 위해서는 근본적으로 아키텍처에 독립적이고 이식성을 보장하는 구조가 요구됩니다

* Java는 이러한 문제를 해결하게 위해 하드웨어 아키텍쳐, 운영체제 인터페이스, 윈도우 시스템에 독립적인 바이트 코드를 사용합니다.

- Java 프로그램은 Windows95/NT, Solaris2.x, Mac OS7.5와 같은 Java가 지원되는 모든 플랫폼상에서 Java 컴파일러에 의해 바이트 코드 형태로 컴파일되고, 인터프리터가 동작하는 Java 가상 기계에 의해 어떤 기종의 시스템에서도 쉽게 해석됩니다.

 

 

자바는 C와 비교할 때 스트링 처리에 있어서 차이를 가지고 있는데, 그 차이점에 대해서 설명하세요.

C/C++에서는 문자의 배열이나, 자바에서는 객체로 취급합니다.

- Java는 모든 것을 객체로 구현합니다. 심지어는 문자열(String)도 클래스로 구현되어 있습니다.

기존 C, C++에서 문자열이란 끝이 널 문자인 문자 배열로 구현되었습니다.

그러나 Java에서는 문자열을 String, StringBuffer 개체로 구현합니다.

그러므로 메모리를 효율적, 안정적으로 사용 가능합니다.

- 객체이므로 NEW 연산자를 통해서 객체 생성과정이 필요하지만, 인용부호(“,”)를 이용하여 문자의 연속으로 생성이 가능합니다.

 

 

클래스와 객체가 가지는 차이점에 대해서 간단히 설명하시오

객체 : 프로그램은 객체로 구성

데이터와 그 데이터를 가공하는 함수를 한데 뭉친 것을 말합니다. 즉 가운데 데이터들을 가지고 있고,주변에는 데이터를 가공하는 Method들로 외부로 들어오는 호출을 모조리 막고(Encapsulation) 있음으로써 프로그램이 서로 연관되는 데이터와 함수들끼리 모을 수 있고, 서로간에 데이터를 바로 접근을 못하기 때문에 프로그램을 고치기가 용이합니다.

 

클래스 : 자바 프로그래밍의 기본 단위

객체 지향 설계는 객체의 생성을 위한 용기로서 클래스 개념을 사용합니다. 이것은 어떤 사물의 특징 목록으로 생각될 수 있습니다. 즉, 데이터 선언이 있고 그 데이터를 처리해 주는 Method들로 둘러싸인 아직 실제로 존재하지 않는 구조를 말합니다. (자료부분+메소드부분)

* 자료 : 객체의 구조를 기술합니다.(변수,상수로 구성)

클래스의 필드라고 부릅니다.

* 메소드 : 객체의 행위를 정의합니다.(작업의 처리 부분과 자료의 접근 형태 등을 기술하는 부분입니다.)

표준 C언어의 함수 형태입니다.

 

객체는 클래스가 실제화 된 것이므로 클래스의 인스턴스(instance)라고 부르고, 클래스는 객체를 정의하기 위한 기본이 되므로 객체를 정의하는 템플릿(template)이라고 부릅니다.

크리에이티브 커먼즈 라이선스
Creative Commons License
by 이동한 2007/08/06 18:42
| 1 |