자바 클래스 튜어

최희창
삼성전자 멀티미디어 연구소
E-mail:hcchoi@khgw.info.samsung.co.kr
URL:http://net.info.samsung.co.kr/~hcchoi/

기존의 C/C++을 이용해서 프로그램을 작성하던 사람들에게는 라이브러리 라는 개념은 아주 친숙한 것이다. 실제 이러한 라이브러리 없이 프로그램을 개발한다는 것은 어쩌면 가능치 않은 일이기도 하다. 예를 들어서 화면에 무언가를 나타내기 위해서 printf()라는 함수부터 먼저 작성해야 한다면 이는 문제가 아닐 수 없다. 따라서 컴파일러를 제공하는 회사에서는 이러한 함수들에 대해서는 한데 모아서 이를 라이브러리의 형태로 제공을 한다. 따라서 프로그래머는 실제 필요한 모든 함수들을 직접 만들 필요가 없이 라이브러리에 있다면 단순하게 불러다가 사용하면 된다. 자바의 경우에는 프로그램에서 많이 사용되는 클래스들을 한데 묶어서 패키지라는 형태로 제공을 한다. 자바의 클래스 패키지를 비록 기능상에 많은 차이는 있지만 마이크로소프트의 VC++의 MFC나 볼란드사의 OWL과 같은 개념으로 이해를 하면 큰 무리는 없을 것이다.

자바에서는 서로 관련되는 클래스들을 모아서 패키지라는 것으로 제공한다고 했는데, 실제 JDK 1.0에 들어가 있는 클래스 패키지에는 다음과 같은 것들이 있다.

이외에도 다음과 같은 클래스 패키지들이 있다.

  • sun.tools.debug

    다음은 위에서 나열한 각각의 클래스 패키지 중에서 일반적으로 많이 사용되는 클래스들에 대해서 그 사용법에 대해서 알아보기로 한다.

    1. 자바 애플렛 패키지

    자바 애플렛 패키지에는 애플렛을 만드는데 기본이 되는 Applet 클래스를 제공한다. Applet 클래스에서는 이미지 데이터나 오디오 데이터를 다룰 수 있는 함수들을 별도로 제공한다.

    실제 애플렛 패키지에는 Applet이라는 클래스이외에는 없다. 따라서 여기에서 Applet의 메쏘드들의 쓰임세에 대해서 알아보기로 한다.

    먼저 애플렛의 라이프 사이클(생성, 실행, 파괴)에 관계된 메쏘드들에 대해서 다음의 코드를 통해서 살펴보기로 한다.

    import java.awt.Graphics;
    public class Simple extends java.applet.Applet {
    public void init() {
     System.out.println("Initilize!");
    }
    public void start() {
     System.out.println("Start!");
    }
    public void stop() {
     System.out.println("Stop!");
    }
    public void destroy() {
     System.out.println("Destroy!");
    }
    public void paint(Graphics g) {
    g.drawRect(0, 0, size().width - 1, size().height - 1);
    }               
    

    자바 애플렛 실행 가능한 브라우져가 애플렛이 담겨져 있는 HTML 문서를 읽어오게 되면 해당 애플렛이 네트워크나 파일 시스템을 통해서 처음으로 브라우져에 로드될 때 실행되는 함수가 init()이라는 함수이다. 따라서 여기에서는 애플렛에서 필요한 초기화 작업들을 하기에 알맞은 장소이다. 이렇게 init() 함수가 불려지고 난 다음에는 start()라는 함수가 불려져서 실제 작업을 수행할 수 있게끔 해준다. 만약 사용자가 현재 애플렛이 수행되고 있는 페이지에서 다른 페이지로 이동하는 경우는 애플렛의 수행을 멈추는 것을 알려주기 위해서 stop()이라는 함수가 불려진다. 따라서 stop()에서는 실제 애플렛의 동작으로 멈추기 위해서 필요한 작업을 해준다. 마지막으로 더 이상 애플렛이 필요 없어지는 경우에는 destroy()가 불려진다. 참고로 destroy()가 불려지기 전에 반드시 stop()이 불려지므로, 애플렛 실행 중단에 따른 여러 가지 클린업 작업들은 일반적으로 stop()에서 해준다.

    다음은 실제 위 메쏘드들이 실제 코드에서 어떻게 사용되어지는가를 TumbleItem.java코드를 통해서 살펴보기로 한다. TumbleItem.java코드의 첫 부분을 보면 다음과 같은 init()문장이 있다.

    /**
    * Initialize the applet. Get attributes.
    */
    public void init() {
     String at = getParameter("img");
     dir = (at != null) ? at : "images/tumble";
     at = getParameter("pause");
     pause = (at != null) ? Integer.valueOf(at).intValue() : 3900;
     at = getParameter("offset");
     offset = (at != null) ? Integer.valueOf(at).intValue() : 0;
     at = getParameter("speed");
     speed = (at != null) ? (1000 / Integer.valueOf(at).intValue()) : 100;
     at = getParameter("nimgs");
     nimgs = (at != null) ? Integer.valueOf(at).intValue() : 16;
     at = getParameter("maxwidth");
     maxWidth = (at != null) ? Integer.valueOf(at).intValue() : 0;
    }
    

    위의 코드에서 하는 일들을 가만히 살펴보면 나중에 애플렛에서 사용될 변수들을 getParameter()라는 메쏘드를 통해서 읽어와서 세팅하는 것임을 알 수 있다. 일반적으로 init()에서는 위와 같이 주로 애플렛에서 사용할 변수들을 초기와 하거나, 이미지와 오디오 등의 리소스들을 미리 읽어오는 일이나, 애플렛의 크기를 재조정하는 작업들을 수행한다. 그 다음에 start()문에 대해서 TumbleItem.java에서 살펴보기로 한다.

    /**
    * Start the applet by forking an animation thread.
    */
    public void start() {
     if (kicker == null) {
         kicker = new Thread(this);
         kicker.start();
     }
    }
    

    일반적으로 start()문에서는 애플렛의 동작 수행에 관계된 일을 수행한다고 했으므로, 작업 쓰레드를 하나 만들어서 이를 수행시키는 코드들이 많이 들어간다. 위의 코드에서도 Thread 클래스로 정의된 kicker가 현재 수행중이 아닌가를 검사해서(kicker == null), 수행중이 아니면 새로운 쓰레드를 만들어서 이를 실행시키는 것을 알 수 있다. 쓰레드에 대해서는 나중에 자세히 설명하도록 한다. 그 다음으로 stop()에 대해서 TumbleItem.java코드를 통해서 살펴보면 다음과 같다.

    /**
    * Stop the applet. The thread will exit because kicker is set to null.
    */
    public void stop() {
     if (kicker != null) {
         kicker.stop();
         kicker = null;
     }
    }
    

    위의 stop()에서는 애플렛의 수행을 멈추어야 하므로, 실제 수행되고 있는 쓰레드가 있는 가를 검사해서(kicker != null), 있다면 쓰레드의 수행을 중지시키는 작업을 수행한다.

    마지막으로 destroy()에 대해서는 실제 아무런 일도 할 필요가 없으므로 코드를 넣지 않았다. 참고적으로 실제 init()이나 start(), stop()등에서 아무런 작업도 할 필요가 없는 경우에는 실제 함수를 작성하지 않아도 무방하다.

    애플렛에서 이미지와 오디오 데이터를 다루는 방법에 대해서 살펴보기로 한다. 먼저 이미지 데이터를 다루는 방법에 대해서 살펴보면 다음과 같은 두 가지 메쏘드가 존재한다.

      Image getImage(URL)   
      Image getImage(URL, String)
    

    첫 번째 방법은 이미지파일에 대한 완전한 URL을 기술해주는 방법이고 두 번째는 방법은 이미지에 대한 URL과 이에 상대적인 패스정보를 String으로 넣어주는 방법이다. 참고적으로 애플렛에서 바로 다룰 수 있는 이미지 포맷은 gif와 jpeg포맷의 이미지이다. 다음은 이와 같은 방법을 통해서 이미지를 나타내는 코드이다.

     Image img;
     public void init()
     {
      img=getImage(getDocumentBase(), "face.gif") ;
     }
     public void paint(Graphics g)
     {
      g.drawImage(img, 20, 10,this);
     }
    

    위의 코드에서 실제 이미지를 화면에 나타내는 메쏘드는 Graphics 클래스의 drawImage()이다.

    애플렛에서 오디오를 다루는 방법은 두가지 방법이 있으며 au포맷의 오디오만을 플레이 할 수 있다. 먼저 소리를 내고 싶은 장소에서 다음과 같은 코드를 넣어주면 URL로 지정된 오디오 데이터가 플레이 된다.

      play(URL)
      play(URL, String) 
    

    다음의 방법은 AudioClip이라는 오브젝트를 사용하는 방법으로 오디오 데이터를 읽어와서 해당 메쏘드를 사용해서 플레이하거나 멈추는 방법이 있다.

     AudioClip snd=getAudioClip(URL)   
     AudioClip snd=getAudioClip(URL, String)
     snd.play()
     snd.stop()
     snd.loop()
    

    2. 자바 AWT 패키지

       java.awt.BorderLayout (implements java.awt.LayoutManager)
              java.awt.CardLayout (implements java.awt.LayoutManager) 
              java.awt.CheckboxGroup
              java.awt.Color 
              java.awt.Component (implements java.awt.image.ImageObserver) 
                     java.awt.Button 
                     java.awt.Canvas 
                     java.awt.Checkbox
                     java.awt.Choice 
                     java.awt.Container 
                          java.awt.Panel 
                           java.applet.Applet (java.Applet 패키지)     
                          java.awt.Window 
                               java.awt.Dialog 
                                    java.awt.FileDialog 
                               java.awt.Frame (implements java.awt.MenuContainer) 
                     java.awt.Label 
                     java.awt.List 
                     java.awt.Scrollbar 
                     java.awt.TextComponent 
                          java.awt.TextArea 
                          java.awt.TextField  
              java.awt.Dimension
              java.awt.Event
              java.awt.FlowLayout (implements java.awt.LayoutManager) 
              java.awt.Font 
              java.awt.FontMetrics 
              java.awt.Graphics 
              java.awt.GridBagConstraints (implements java.lang.Cloneable) 
              java.awt.GridBagLayout (implements java.awt.LayoutManager) 
              java.awt.GridLayout (implements java.awt.LayoutManager)
              java.awt.Image      
              java.awt.Insets (implements java.lang.Cloneable)
              java.awt.MediaTracker 
              java.awt.MenuComponent 
                     java.awt.MenuBar (implements java.awt.MenuContainer) 
                     java.awt.MenuItem 
                          java.awt.CheckboxMenuItem 
                          java.awt.Menu (implements java.awt.MenuContainer)
              java.awt.Point 
              java.awt.Polygon
              java.awt.Rectangle
              java.awt.Toolkit          
    

    AWT 패키지에는 GUI에 관련된 클래스들이 들어가 있다. AWT는 기본적으로 개별적인 UI 요소들을 표현하는 Component 클래스들과 이들을 한데 묶을 수 있는 Container라는 클래스들이 제공이 된다. 이러한 관계에서 Container는 다시 하나의 Component로 취급되어질 수 있다. 이는 클래스간의 상관 관계에서도 표현이 되는 것으로 Container 클래스가 Component 클래스의 자식 클래스임을 위의 표를 통해서 알 수 있을 것이다. 또한 Container에 Component들을 배치하기 위해서 LayoutManager 클래스들이 제공되어져서 여러 가지 방법으로 Component들을 위치시킬 수 있는 방법을 제공한다.

    다음은 AWT에서 제공하는 컨테이너의 종류들이다.

    Window상위 레벨의 윈도로 경계선을 가지지 않는다.
    Frame경계선과 제목, MenuBar를 가질 수 있는 상위 레벨 윈도로
    일반적인 자바 어플리케이션의 베이스 클래스로 사용된다.
    Dialog대화상자를 만드는데 사용되어지는 윈도이다.
    FileDialog파일 시스템으로부터 파일을 선택하는데 사용되어지는 윈도이다.
    Panel다른 컨테이너의 내부에서 사용되질 수 있는 컨터이너
    (Applet의 상위 클래스이다).

    다음은 AWT에서 제공하는 컴포넌트의 종류들이다.

    Button 일반적으로 많이 사용되는 누름(push) 버튼
    Canvas페인트를 하거나 사용자로부터 입력을 가로채는데
    사용되며, 사용자 정의 컴포넌트를 만드는데 베이스 클래스로 사용되는
    일반적인 목적의 컴포넌트
    CheckBoxon/off 상태를 가지는 컴포넌트
    Label임의의 위치에 문자열을 나타내는 컴포넌트
    List스크롤 가능한 스트링들의 리스트
    Scrollbar스크롤 가능한 캔버스를 만드는데 사용되어지는 컴포넌트
    TextArea간단한 텍스트-편집 컴포넌트
    TextField양식을 만드는데 사용되어지는 한줄짜리 텍스트 컴포넌트

    여기에서 Component와 Container의 주요 메쏘드 등을 살펴보기로 한다. 먼저 Container의 경우에 다음과 같은 메쏘드들이 존재한다.

    add(Component cmp)지정된 컴포넌트를 컨테이너에 추가시킨다.
    add(String str, Component cmp)지정된 컴포넌트를 컨테이너에 추가시키면서,
    주어진 스트링으로 이름을 붙인다.
    remove(Component cmp)지정된 컴포넌트를 컨터이너에서 삭제시킨다.
    removeAll()컨터이너내의 모든 컴포넌트들을 삭제시킨다.
    getComponents()컨테이너내의 모든 컴포넌트들을 가져온다.
    setLayout(LayoutManager lm)컴포넌트에 대한 배치 관리자를 세팅한다.
    getLayout()현재 컨테이너에서 채용하고 있는 배치 관리자 정보를 가져온다.

    위와 같은 메쏘드 이외에도 컴포넌트에서 정의된 모든 메쏘드를 사용할 수가 있다. 다음은 컴포넌트에서 정의된 메쏘드들을 살펴보기로 한다.

    action(Event, Object)컴포넌트 내에서 액션이 일어나는 경우에 불려진다.
    disable()컴포넌트를 비활성화시킨다.
    enable()컴포넌트를 활성화시킨다.
    handleEvent(Event)컴포넌트 내에서 발생한 이벤트를 처리한다.
    hide()컴포넌트를 숨긴다.
    keyDown(Event, int)키가 눌리어졌을 때 불려진다.
    keyUp(Event, int)키가 눌리어졌다가 띄어질 때 불려진다.
    mouseDown(Event, int, int) 마우스버튼이 눌리어졌을 때 불려진다.
    mouseDrag(Event, int, int)마우스버튼이 눌리어진 채로 이동될 때 불려진다.
    mouseEnter(Event, int, int)마우스가 컴포넌트의 영역에 들어왔을 경우에 불려진다.
    mouseExit(Event, int, int)마우스가 컴포넌트의 영역에서 빠져나갈 때 불려진다.
    mouseMove(Event, int, int)마우스 버튼이 눌리어지지 않은 상태에서 컴포넌트 상에서 움직일 때 불려진다.
    mouseUp(Event, int, int) 마우스 버튼이 눌리워졌다다가 원상태로 될 때 불려진다.
    move(int, int)컴포넌트를 새로운 위치로 이동시킨다.
    show()컴포넌트를 나타난다.
    paint(Graphics)컴포넌트가 새로 그려져야 하는 경우에 불려진다.
    repaint()컴포넌트를 새로 그리도록 요청한다.
    update(Graphics)repaint 요청이 들어오는 경우에 불려지는 것으로
    여기에서는 기본적으로 paint()를 부른다.

  • Frame 샘플
    import java.awt.*;
    public class MyApp extends Frame
    {
            // "final" variables are constants
            static final int H_SIZE = 300;
            static final int V_SIZE = 200;
            public MyApp()
            {
                    super("My First Application");
                    Panel p = new Panel();
                    p.add(new Button("Ok"));
                    p.add(new Button("Cancel"));
                    add("South", p);
                    pack();
                    resize(H_SIZE, V_SIZE);
                    show();
            }
            public static void main(String args[])
            {
                    new MyApp();
            }
    }
    

    각 컴포넌트들의 샘플

    Button 클래스
     Button button;
     button = new Button("OK");
     add(button);
    
    Choice 클래스
     Choice SelectOne = new Choice();
    
     SelectOne.addItem("Seoul");
     SelectOne.addItem("Pusan");
     SelectOne.addItem("daejeon");
     
     add(SelectOne);
    
    CheckBox/CheckBoxGroup 클래스
     CheckBoxGroup cbgrp = new CheckBoxGroup();
     CheckBox chk1= new CheckBox("company", cbgrp, ture);
     CheckBox chk2= new CheckBox("school", cbgrp, false);
     CheckBox chk3= new CheckBox("org", cbgrp, false);
     
     add (chk1);
     add (chk2);
     add (chk3);
    
    Label 클래스
     Label l1 = new Label("Welcome to the Workshop!");
     add (l1);
    
    List 클래스
     List lst = new List(3, false);
     lst.addItem("Company");
     lst.addItem("School");
     lst.addItem("Org");
    
     add(lst);
    
    TextField/TextArea 클래스
     TextField tf = new TextField(15);
     TextArea ta = new TextArea(3, 4);
    
     add(tf);
     add(ta);
    
    Scrollbar 클래스
     Scrollbar sb = new Scrollbar(Scrollbar.VERTICAL, 0, 32, 0, 128);
       // orientation, initial value, visible size, min, max
     add(ab);
    
    

    Layout Manager의 종류 및 실제 예

    FlowLayout
    Panel의 디폴트 레이아웃 매니저이다. 컴포넌트들을 왼쪽에서 오른쪽으로 배치시키면서 중앙에 오도록 한다. 필요한 경우 줄을 바꾸어서 컴포넌트들을 배치시킨다.
     button1 = new Button("1");
     button2 = new Button("2");
     button3 = new Button("3");
     add(button1);
     add(button2);
     add(button3);
    
    BorderLayout
    모든 Windows 클래스의 기본적인 레이아웃 매니져로, 컴포넌트들을 다섯 가지 방향으로 위치시키는데, 동, 서, 남, 북 그리고 중앙이다.
     setLayout(new BorderLayout());
     button1 = new Button("1");
     button2 = new Button("2");
     button3 = new Button("3");
     button4 = new Button("4");
     button5 = new Button("5");
    
     add("North", button1);
     add("East", button2);
     add("South", button3);
     add("West", button4);
     add("Center", button5);
    
    GridLayout
    컴포넌트들을 주어진 열과 행으로 같은 크기로 배치시키는 레이아웃매니져이다.
     setLayout(new GridLayout(2,3));
     button1 = new Button("1");
     button2 = new Button("2");
     button3 = new Button("3");
     button4 = new Button("4");
     button5 = new Button("5");
     button6 = new Button("6");
    
     add(button1);
     add(button2);
     add(button3);
     add(button4);
     add(button5);
     add(button6);
    
    GridBagLayout
    가장 유연하고 정교하게 컴포넌트들을 배치시킬 수 있는 레이아웃 매니져로 컴포넌트들을 수직이나 수평선에 줄을 맞추어서 배치시킬 수 있으며, 컴포넌트들이 서로 다른 크기이어도 된다.
    CardLayout
    시간에 따라서 다른 컴포넌트들을 표시해야 하는 경우에 사용되어지는 레이아웃매니져로 일반적으로 Choice 클래스와 같이 사용되어진다.

    이번에는 이벤트의 처리에 대해서 알아보도록 한다. 일반적으로 이벤트(Event)를 처리하는 경우가 키보드와 마우스 그리고 GUI가 관련되어져 있다. 모든 이벤트들은 handleEvent(Event evt)에서 처리되어져 지는데, 몇몇 이벤트의 경우에는 미리 정의된 핸들러 루틴들이 존재한다.

    키보드 관련 이벤트의 처리는 KeyDown()과 KeyUp()에서 처리하며, 마우스 관련 이벤트는 mouseXYZ()와 같은 형태의 이벤트 루틴에서 처리할 수 있으며, GUI 이벤트는 action()에서 처리되어질 수 있다.

    다음의 코드는 키입력을 처리하는 두 가지 방법에 대해서 보여준다.

    public boolean keyDown(Event evt, int key)
    {
            Sytem.out.println(key);
            return false;
    }
    
    public boolean handleEvent(Event evt)
    {
            switch(evt.id)
            {
                    case Event.KEY_PRESS:
                    {
                            System.out.println(evt.key);
                            return true;
                    }
                    default:
                            return false;
            }
    }
    

    다음의 코드는 버튼이나 메뉴아이텀에 대한 이벤트 처리 루틴을 보여준다.

    public boolean action(Event evt, Object arg)
         {
                if(evt.target instanceof Button)
                 {
                         if("OK".equals(arg))
                         ...
                         return true;
                 }
                 else if(evt.target instanceof MenuItem)
                 {
                         if("File".equals(arg))
                         ...
                         return true;
                 }
                 return false;
    }
    

    3. 자바 유틸리티 패키지

               java.util.BitSet (implements java.lang.Cloneable)
               java.util.Date                
               java.util.Dictionary 
                     java.util.Hashtable (implements java.lang.Cloneable) 
                           java.util.Properties
               java.util.Observable
               java.util.Random
               java.util.StringTokenizer (implements java.util.Enumeration)
               java.util.Vector (implements java.lang.Cloneable) 
                     java.util.Stack
    


    자바 유틸리티 패키지에는 자바 프로그램 시에 사용되어지는 여러 가지 유틸리티들이 들어가 있다. 주요한 클래스들로는 시간을 다룰 수 있는 Date 클래스와 키를 가지고 값을 가져오는 Dictionary, Hashtable이 있고, 임의의 데이터를 저장할 수 있는 Vector클래스와 스택에 관한 Stack, 랜덤 값이 관계된 Random값과 스트링에 있는 토큰들을 분리해내는 StringTokenizer 클래스 등이 들어가 있다. 다음은 주요 유틸리티 클래스들의 사용법에 대한 설명이다.

  • Date
    import java.util.Date;
    class printDate {
     public static void main(String args[]) 
        {
      Date today = new Date();
      System.out.println(today);
      System.out.println("Year "+today.getYear());
      System.out.println("Month "+today.getMonth()); // 0 - 11
      System.out.println("Date "+today.getDate()); // 1 - 31
      System.out.println("Day "+today.getDay()); // 0 -6
     }
    }
    

  • StringTokenizer
    import java.util.StringTokenizer;
    class STokTest {
     public static void main(String args[]) 
        {
     String s = "this is a sample text";
            StringTokenizer st = new StringTokenizer(s);
            while (st.hasMoreTokens()) {
                    System.out.println(st.nextToken());
            }
    }
    

  • Stack

    다음은 Stack 클래스의 메쏘드들이다.
    boolean empty()스택이 비어있는가를 체크한다.
    Object peek()스택의 맨 위에 있는 내용을 살펴본다.
    Object pop()스택에서 오브젝트를 하나 가져온다.
    Object push(Object)스택에 오브젝틀 하나 추가한다.
    int search(Object)스택에 특정 오브젝트가 있는 가를 검사해서
    그 위치를 알려준다.

    4. 자바 언어 패키지

               java.lang.Boolean 
               java.lang.Character     
               java.lang.Class 
               java.lang.ClassLoader
               java.lang.Compiler 
               java.lang.Math
               java.lang.Number 
                      java.lang.Double 
                      java.lang.Float 
                      java.lang.Integer 
                      java.lang.Long
               java.lang.Process
               java.lang.Runtime
               java.lang.SecurityManager
               java.lang.String 
               java.lang.StringBuffer 
               java.lang.System
               java.lang.Thread (implements java.lang.Runnable) 
               java.lang.ThreadGroup 
               java.lang.Throwable 
    


    자바 언어 패키지 내에는 자바의 모든 클래스들의 기본이 되는 Object클래스를 비롯하여, 기본 데이터 타입에 관련된 클래스들, Integer, Long, Float, Double등이 클래스들이 존재한다. 또한 상수 스트링을 다루기 위한 String 클래스와 값과 크기가 변하는 스트링을 다루기 위한 StringBuffer클래스가 들어가 있으며, System이라는 클래스가 들어가 있어서 일반적인 입출력에 관련된 메쏘드들이 모아져 있다. 그리고 수학적인 함수들을 한데 모아놓은 Math라는 클래스가 있어서 여러 가지 수학함수들을 사용할 수가 있다. 또한 쓰레드 처리를 위한 Thread 클래스가 들어가 있다. 시스템 명령어들을 실행시키기 위한 Rumtime클래스 등이 제공되어서 자바 어플리케이션내에서 다른 프로그램들을 호출할 수 있는 기능을 제공한다. 다음은 주요한 클래스들에 대한 설명이다.

  • String and StringBuffer

    String 클래스는 프로그램 내에서 그 내용이 변하지 않는 문자열을 다룰 때 사용하며, StringBuffer는 문자열의 내용이 변경되는 경우에 사용되어진다. 다음은 String/StringBuffer 클래스의 인스턴스를 만드는 방법이다.

    String  s1 = new String("WWW-KR");
    String s2 = new String(" 3rd Workdshop");
    StringBuffer sb = new StringBuffer("Welcome!");
    

    다음은 String/StringBuffer의 사용법을 나타내는 예이다.
    class Reverse{
     public static String reverse(String src) {
     int i, len = src.length();
     StringBuffer dest=new StringBuffer(len);
     for (i=(len-1); i >=0; i--)
      dest.append(src.charAt(i));
     }
     return dest.toString();
     }
    }
    

  • Math

    Math 클래스는 다른 클래스들과는 달리 모든 메쏘드와 변수들이 static으로 선언되어져 있다. 따라서 new 연산자를 통해서 인스턴스를 새로이 만들 수가 없다. Math 클래스에서 지원하는 수학식으로는 abs, sin, cos, tan, asin, acos, atan, atan2, exp, log, sqrt, ceil, floor, rint, pow, round, random, max, min이 있으며, Math.E와 Math.PI가 제공된다.

    import java.lang.*;
    import java.io.*;
    
    class MathTest{
     public static void main(String args[]) 
        {
      int i;
      i = Math.max((int)25, (int)12);
    
      double rnd;
      rnd =Math.random();
      
      i  = Math.pow((doubel)3, (double)4);
     }
    }
    

  • Runtime

    Runtime 클래스는 시스템 명령어를 수행하는데 사용되어진다. 사용법은 다음과 같다.
    import java.lang.Runtime;
    import java.io.*;
    
    class RunNote{
     public static void main(String args[]) 
        {
      try
      {
       Runtime rt=Runtime.getRuntime();
       rt.exec("notepad"); 
      } catch (IOException e)
      {
       System.out.println("Error!");
      }
     }
    }
    


    5. 자바 입출력 패키지

               java.io.File  
               java.io.FileDescriptor
               java.io.InputStream 
                      java.io.ByteArrayInputStream 
                      java.io.FileInputStream 
                      java.io.FilterInputStream 
                           java.io.BufferedInputStream 
                           java.io.DataInputStream (implements java.io.DataInput) 
                           java.io.LineNumberInputStream 
                           java.io.PushbackInputStream 
                      java.io.PipedInputStream 
                      java.io.SequenceInputStream 
                      java.io.StringBufferInputStream
               java.io.OutputStream 
                      java.io.ByteArrayOutputStream 
                      java.io.FileOutputStream 
                      java.io.FilterOutputStream 
                           java.io.BufferedOutputStream 
                           java.io.DataOutputStream (implements java.io.DataOutput) 
                           java.io.PrintStream 
                      java.io.PipedOutputStream 
               java.io.RandomAccessFile (implements java.io.DataOutput, java.io.DataInput)
               java.io.StreamTokenizer 
    


    자바 입출력 패키지는 C++의 iostreams과 유사한 구조로 설계되어져 있다. 이 안에는 파일을 다루기 위한 File 관련 클래스들이 들어가 있고, 입력 스트림을 다루는 InputStream관련 클래스들, 출력 스트림을 다루는 OutputStream등이 들어가 있다. 또한 랜덤 파일 억세스를 위한 RamdonAccessFile이라는 클래스를 제공한다. 또한 스트림에서 토큰을 뽑아내는 StreamTokenizer 클래스를 제공한다.

    자바에서 사용되는 표준 입출력방법에 대해서 살펴보면 이는 java.lang.System 클래스를 통해서 이루어진다. 표준 입력(stdin)의 경우에 이는 키보드를 대상으로 하는 것으로 System.in이 사용되어지며 이는 InputStream의 한 인스턴스로서 데이터를 읽는 read() 메쏘드와 입력스트림에서 몇 바이트를 뛰어넘는 skip() 메쏘드를 제공한다. 표준 출력(stdout)과 에러(stderr)에 대해서는 각각 system.out과 System.err이 사용되는데 이는 PrintSream을 가지고 구현되어진 것으로 터미널 스크린 상으로 출력하게끔 되어져 있다. 여기에서는 print()와 println()과 같은 메쏘드를 사용할 수 있다. 다음의 코드는 표준 입출력을 다루는 샘플 코드이다.

    import java.io.*;
    public class SIO
    {       
       public static void main(String args[]) 
       {
     int ch;
     while ((ch=System.in.read()) != -1)
     {
      System.out.print((char)ch);
     }
     System.out.println();
       }
    }
    

    그 다음으로 File 클래스에 대해서 살펴보기로 한다. io 패키지에 있는 File 클래스는 파일에 관한 기본적인 정보를 제공해주는 클래스이다. 가령 크기나 만들어진 날짜 등 파일 자체에 대한 정보를 가지고 있는 것으로, 이는 실제 파일 입출력하고는 직접적인 관계가 없다. 실제 File 클래스를 만드는 방법은 다음과 같다.

    File docfile = new File("c:\doc\report.doc");
    File docfile = new File("report.doc");
    File dir = new File("c:\doc");
    

    다음은 File 클래스의 주요 메쏘드들에 대해서 살펴보기로 한다.
    String getName()파일의 이름을 가져온다
    String getPath()파일의 경로를 가져온다
    String getAbsolutePath()파일의 절대 경로를 가져온다
    String getParent()부모 디렉토리를 가져온다
    boolean canRead()파일을 읽을 수가 있는기 검사한다
    boolean canWrite()파일에 쓸수가 있는가를 검사한다
    boolean exists() 파일이 존재하는 가를 검사한다
    boolean isFile() 파일인가를 검사한다
    boolean isDirectory()디렉토리인가를 검사한다
    boolean isAbsolute()절대 경로 인가를 검사한다
    boolean renameTo(File dest)파일 이름을 다른 이름으로 변경한다
    boolean delete() 파일을 삭제한다
    long lastModified() 최근 변경일에 대한 정보를 나타낸다
    long length()파일의 길이에 대한 정보를 나타낸다
    String toString()파일이름을 String 타입으로 변환한다
    String[] list()디렉토리의 내용을 리스팅한다
    boolean mkdir()새로운 디렉토리를 만든다

    다음은 입력 스트림에 대해서 살펴보기로 한다. 입력 스트림은 입력 소스로 부터 데이터를 읽어오는데, 입력소스로는 파일이나 스트링 또는 메모리 등이 올 수 있다. 모든 입력 스트림은 InputStream 클래스에서 파생되어진다. 다음은 InputSteam에서 정의된 메쏘들이다.

    available()블록킹이 되지 않고 읽을 수 있는 바이트의 개수를 넘겨준다
    close()입력 스트림을 닫는다
    mark(int)입력 스트림내의 현재 위치에 표시를 해둔다
    markSupported()입력 스트림이 마크/리셋을 지원하는 가를 판별한다
    read()한 바이트의 데이터를 읽어온다
    read(byte[])바이트 배열로 데이터를 읽어온다
    read(byte[], int offset, int length)지정된 위치에서 지정한 수 만큼 데이터를 읽어온다
    reset()최근에 마크된 위치로 스트림을 재위치시킨다
    skip(long)지정한 바이트 수만큼 스킵한다

    주요한 InputStream의 파생 클래스들에 대해서 살펴보기로 한다. 먼저 파일 입출력을 다루는 경우에는 FileInputStream을 사용한다. 이는 순차적인 방법으로 한 바이트씩 파일에 있는 데이터를 가져올 수가 있다. 파일에 대해서 FileInputStream을 여는 방법은 다음과 같다.

    File  doc=new File("report.txt");
    FileInputStream docFile = new FileInputStream(doc);
    FileInputStream docfile = new FileInputStream("report.txt");
    

    위와 같은 방법으로 생성한 스트림에 대한 읽기는 위의 InputStream에서 정의한 메쏘드들을 통해서 할 수가 있다. 입력이 끝난 스트림에 대해서는 close() 메쏘드를 통해서 명시적으로 스트림을 닫을 수도 있고 또는 시스템의 가비지 콜랙터에 의해서 자동적으로 닫히는 방법이 있다.

    그 다음으로 DataInputStream이 있는데, 이는 FileInputStream과 매우 유사하며, 기본 데이터 타입으로 바로 읽어들일 수가 있으며 라인단위의 입력을 처리할 수 있다. 따라서 이들은 FileInputStream과 연동해서 사용되어진다. 다음은 DataInputStream의 대표적인 메쏘드들의 형태이다.

    readByte()
    readChar()
    readShort()
    readInt()
    readLong()
    readLine()
    

    다음은 FileInputStream과 DataInputStream을 연동해서 사용하는 방법을 보여준다.

    import java.io.*;
    public class List 
    {       
          public static void main(String args[]) 
          {
                  FileInputStream in = null;
                  String   line;
           int linenum=0;
    
                    try 
                    {
                            in = new FileInputStream(args[0]);
                    } 
                    catch (Throwable e) 
                    {
                            System.out.println("Usage: java List file");
                            System.exit(1);
                    }
    
                    DataInputStream dis = new DataInputStream(in);
    
                    // End-of-File is -1, but in this case as long as the
                    // string returned is not null, continue
                    try 
                    {
                            while ((line = dis.readLine()) != null) 
                                    System.out.println(++linenum+": "+line);
                            in.close();
                    }
                    catch(IOException e)
                    {
                            System.out.println("I/O Error");
                            System.exit(1);
                    }
            }
    }
    

    다음은 기타 입력 스트림에 대한 간략한 사용용도를 나타낸 것이다.

    SequenceInputStream여러개의 입력 스트림들을 하나의 스트림으로 처리하는 경우
    PipedInputStream파이프를 통해서 데이터를 읽어오는 경우
    (일반적으로 PipedOutputStream과 연동되어서 사용되어진다)
    ByteArrayStreamBuffer바이트 배열(버퍼)로부터 데이터를 읽어오는 경우
    StringBufferInputStream StringBuffer로 부터 데이터를 읽어오는 경우

    출력 스트림에 대해서 살펴보기로 한다. 출력 스트림의 경우에는 입력 스트림과 그 구성이 유사하다. 모든 출력 스트림들은 OutputStream으로 부터 파생되어진다.

    다음은 OutputStream의 기본적인 메쏘드들이다.

    close()스트림을 닫는다
    flush()스트림의 내용을 지운다
    write(int)한 바이트를 출력한다.
    write(byte[])여러 바이트를 스트림에 출력한다.
    write(byte[], int offset, int len)바이트 배열내에 지정된 위치에 지정한
    크기만큼을 스트림에 출력 한다.

    파일 출력시에는 FileOutputStream을 사용하는데, 이는 다음과 같은 방법으로 정의한다.

    FileOutputStream fout = new FileOutputStream("result.rpt");
    

    DataInputStream에 대응되는 것으로 DataOutputSteam이 있다. DataOutputSteam의 주요 메쏘들들을 살펴보면 다음과 같다.

    writeBoolean(boolean) 
    writeByte(int) 
    writeBytes(String) 
    writeChar(int) 
    writeChars(String) 
    writeDouble(double) 
    writeFloat(float) 
    writeInt(int) 
    writeLong(long) 
    writeShort(int) 
    

    마지막으로 RandomAccessFile 클래스에 대해서 알아보기로 한다. 먼저 RandomAccessFile의 인스턴스를 만드는 방법은 다음과 같다.

    RandomAccessFile rdnfile = new RandomAccessFile("\doc\score.db","rw");
    

    위의 파일 생성자의 두 번째 인자는 모드를 지정하는 것으로 "r"만 사용하면 읽기 전용 모드임을 나타내고, "rw"는 읽기와 쓰기가 동시에 가능하다는 것을 의미한다. 다음은 RandomAccessFile의 주요 메쏘드들이다.

    long getFilePointer()현재의 파일 포인터의 위치를 리턴한다
    void seek(long pos)주어진 위치로 파일 포인터를 이동시킨다
    long length()파일의 크기를 리턴하면서 파일 포인터를 파일의 마지막으로 옮긴다

    6. 자바 네트워크 패키지

               java.net.ContentHandler
               java.net.DatagramPacket 
               java.net.DatagramSocket
               java.net.InetAddress
               java.net.ServerSocket 
               java.net.Socket 
               java.net.SocketImpl
               java.net.URL 
               java.net.URLConnection 
               java.net.URLEncoder 
               java.net.URLStreamHandler
    

    자바 네트웍크 패키지에는 일반적인 TCP/IP 프로그램을 작성하기 위한 Socket 클래스와 Datagram 클래스들이 존재해서 UDP 소켓과 패킷을 다룰 수 있는 클래스를 제공한다. 또한 웹 상의 리소스들을 다루기 위한 URL이라는 클래스가 있어서 URL로 표기되는 웹 객체들을 손쉽게 다룰 수가 있다.

    먼저 URL 클래스에 대해서 살펴보면 이는 웹 상의 리소스를 가리키는 객체로 사용되는 것으로, 이미지나 오디오를 다루는데 있어서 사용되어진다. 다음은 URL을 사용해서 이미지를 가져오는 방법을 예로 나타낸 것이다.

    URL imgsrc = new URL("http://www.server.com/image");
    Image img = getImage(imgsrc, "landscape.gif");
    

    인터넷 주소를 다루기 위한 클래스로 자바에서는 InetAddress라는 클래스를 제공한다. InetAddress는 다음과 같은 메쏘들을 제공한다.

    InetAddress getByName(String host) 주어진 스트링으로 표현된 호스트에 대한 인터넷 어드레스를 리턴한다. 호스트 이름이 널인 경우에는 디폴트로 로컬 호스트의 주소를 리턴한다.

    InetAddress getLocalHost() 로컬 호스트의 인터넷 어드레스를 리턴한다.
    String toString()인터넷 어드레스를 스트링의 형태로 변환시켜준다.
    String getHostName()주소에 해당하는 호스트 이름을 읽어온다.

    다음은 InetAddress 클래스의 사용에 대한 샘플 코드이다.

    import java.net.*;
    
    public class inet{
     public static void main(String args[])
     {
      int i;
      InetAddress localhost=null;
      try {
       localhost = InetAddress.getLocalHost();
      } catch (UnknownHostException e)
      {
       System.out.println("can not determin host");
       System.exit(0);
      }
    
      System.out.println("hostname : " + localhost.getHostName());
      System.out.println("address : " + localhost.toString());
     }
    

    자바에 있어서 가장 간단한 TCP/IP 소켓 연결의 경우에 다음과 같은 모델에 따른다. 서버에서는 소켓을 하나 만들어 놓고 타임아웃 기간을 설정해 놓고 클라이언트로부터 연결을 기다린다. 클라이언트에서는 호스트와 포트번호를 이용해서 연결을 맺은 다음에, 클라이언트와 서버간에는 InputStream과 OutputStream을 이용해서 서로 데이터를 주고받는다.

  • TCP/IP 프로그램의 예
  • 간단하게 TCP/IP 서버/클라이언트 응용 프로그램의 기본적인 구조에 대해서 알아보기로 한다. 먼저 서버의 경우는 가장 기본적인 틀을 다음과 같다.

    import java.net.*;
    import java.io.*;
    
    class TypicalServer {
     public static void main(String args[])
     {
      ServerSocket  servsc;
      Socket  sc;
      OutputStream   out;
      int  portnum=5555;
      int  timeout=500;
      try 
      {
       servsc = new ServerSocket(portnum,timeout);
      } catch (IOException e)
      {
       System.out.println("Socket Error!");
       System.exit(0);
      }
      while (true)
      {
      try 
      {
       sc=servsc.accept();
       out=sc.getOutputStream();
       // prepare sending data into the char_data
       while (no_data_to_be_sent)
        out.write(char_data);
       sc.close();
      } catch (IOException e)
      {
       System.out.println("Error!");
       System.exit(0);
      }
      }
     }
    }
    

    다음은 위의 전형적인 서버에 대응하는 클라이언트의 구조이다.

    import java.net.*;
    import java.io.*;
    
    class TypicalClient {
     public static void main(String args[])
     {
      Socket  clientsc;
      InputStream  inSc;
      int  data;
    
      try
      {
       clientsc = new Socket("jupiter.kr", 5555 );
       inSc = clientsc.getInputStream();
       while ((data=inSc.read()) != -1)
       {
        System.out.print((char)data);
       }
       System.out.println();
       clientsc.close();
      } catch (IOException e)
      {
       System.out.println("Socket Error!");
       System.exit(0);
      }
     }
    }
    

    7. 결론


    지금까지 자바 개발 환경에서 제공해주는 클래스 패키지들에 대해서 살펴보았다. 실제 클래스 하나 하나에 대해서 다루기보다는 각 패키지들의 특성과 주요한 클래스들을 위주로 살펴보았다. 실제 자바에 있어서 클래스 패키지의 이해는 실제 자바 프로그램을 작성하려는 사람들에게는 필수적인 것으로, 자바 프로그램 개발 중에도 계속해서 참조하여야 할 부분이다. 현재 제공되는 자바 클래스 패키지는 아주 기본적인 것들만이 들어가 있어서 멀티미디어 응용프로그램이나 3D 그래픽, 데이터베이스 엑세스 등에 대한 내용들은 포함되어져 있질 않다. 하지만 이러한 부분들도 조만 간에 기본적인 클래스 패키지로 들어가게 될 것이다.

    참고 문헌

    1. Arthur van Hoff, Sami Shaio, Orca Starbuck, "HOOKED on Java", Addison-Wesley, 1996
    2. Tim Ritchey, "Java!", New Riders Publishing, 1995
    3. The Java Tutorial http://java.sun.com/tutorial/index.html
    4. Nelson Yu, AWT Tutorial, 1996, http://ugweb.cs.ualberta.ca/~nelson/java/AWT.Tutorial.html
    5.JAVA Programming Training http://www.sunsales.com/java/

    1996/3/11, 최희창