336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
메모리 부족 관련 질문들이 있어서 정리 합니다. (기억을 더듬어 작성하는거라 잘못된 부분이 있으면 댓글로 말씀주세요)

안드로이드에서 OutOfMemoryError라 발생하는 가장 많은 경우는 바로 비트맵 로딩때문에 발생합니다. 
그 경우 Logcat에서 다음과 같은 메시지를 보실 수 있습니다.

"java.lang.OutOfMemoryError: bitmap size exceeds VM budget"

안드로이드는 애플리케이션 프로세스별로 메모리가 제한되어있다는 것은 다 아실텐데 (16M, 24M, 32M등)  
문제는 위의 메모리 에러가 DDMS에서 가장 쉽게 확인할 수 있는 메모리 값인 VM Heap 사이즈와는 크게 상관없이 발생합니다.
Bitmap을 로딩할 경우 VM 내의 힙메모리를 사용하는게 아니라 VM밖의 Native 힙메모리 영역을 사용하기때문입니다.

0. 가용 메모리의 확인 

아래의 API들을 활용해서 Native Heap 값을 확인할수 있습니다.
Debug.getNativeHeapSize(), Debug.getNativeHeapFreeSize(), Debug.getNativeHeapAllocatedSize()
위 사이즈들은 단말별, 버전별로 조금씩 달라질수 있으니 레퍼런스 폰을 기준으로 약간 여유를 두는 것이 좋을겁니다.

해결 방법은 이미 많은 분들이 작성한 글들이 있는데 정리해보면

1. 아주 큰 이미지 파일을 불러오는 경우 BitmapFactory.Options.inSampleSize 설정을 통해 축소해서 메모리에 로드해야합니다.


2. 이미지의 경우 시스템이 알아서 판단해서 적합한 형식으로 로딩하는데 디폴트인 RGB8888(픽셀당 4바이트)로 로딩하는 경우가 
   많습니다. 이미지를 많이 사용하는 게임등의 경우 투명 이미지는 RGB4444, 불투명 이미지는 RGB565로 충분한 경우가 많으니 
   BitmapFactory.Options.inPreferredConfig 설정값을 어떻게 주고 있는지 확인해보시기 바랍니다. 

3. 더이상 쓰지않는 Bitmap의 경우 Recycle 을 호출해서 바로 가용 메모리를 늘려줍니다.

   bitmap.recycle(); bitmap = null;

  ((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle();


4. 메모리 릭이 발생하지는 않는지 확인하는것은 기본이겠죠.




메모리 관련해서는 저도 확실하게 모르는 부분이 있으니 댓글로 추가 정보 주시면 감사하겠습니다.


블로그 이미지

By훈트

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
비트맵 관련 앱에서 많이 발생하는 힙메모리 관련 오류 해결하기
개발 환경 - 안드로이드 2.1

1. 액티비티
    - onCreate에서 dalvik 버추얼 머신에게 힙메모리 임계값 지정하기 (70%)
       dalvik.system.VMRuntime.getRuntime().setTargetHeapUtilization(0.7f); --> 메인 액티비티에서 한번만 지정

    - onDestroy 이벤트에서 모든 지역변수 null 처리히기, 모든 비트맵 인스턴스 변수 recycle 시키기,
      메인앱에서 System.gc() 한번 호출하기
      
    - dalvik 버추얼 머신에게 dalvik.system.VMRuntime.getRuntime().runFinalizationSync()를
      호출하여 강제로 클래스들의 finalization 호출하기

2. 뷰를 상속한 차일드뷰
    - destroyDrawingCache 메소드를 상속 받아서 이부분에서 비트맵 인스턴스들 recycle 및 null 처리하기

제가 그래픽 관련 앱을짜면서 가장 애먹은 부분이 힙메모리 부분이었습니다.

힙모메리가 한계값까지 계속 늘어나기만 하고 줄어들지 않아서 결국에는 앱이 강제 종료 되는 현상이
계속 발생하더군요.. 구글링으로 여기저기 뒤지다가 안드로이드 플랫폼에서는 앱을 사용자가 종료를
시켜도 실제로는 메모리에 상주해 있어서 메모리가 계속 늘어나는 현상이 있다고 합니다.

블로그 이미지

By훈트

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
String -> Date 타입

DateFormat sdFormat = new SimpleDateFormat("yyyyMMdd");
Date tempDate = sdFormat.parse("20100222");

주의할 점..
" " 내부에 들어가는 내용대로 String 데이터가 입력되어 있어야 파싱이 된다.


Date -> String 타입

DateFormat sdFormat = new SimpleDateFormat("yyyyMMdd");
Date nowDate = new Date();
String tempDate = sdFormat.format(nowDate);

주의할 점..
" " 내부에 들어가는 내용대로 포멧되어 String 데이터로 리턴된다.

블로그 이미지

By훈트

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
BitmapFactory Class에서 Stream을 읽어오는 기능을 하는데, Stream을 다 읽어 오기전에 연결을 다 끊어 NULL을 반환할 경우가 있다. 아래 처럼 하면 해결 될 듯..

HttpGet httpRequest = null;

URL url = new URL(CommunicationManager.getUrlEncode(url));
httpRequest = new HttpGet(url.toURL());
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = (HttpResponse)httpclient.execute(httpRequest);
HttpEntity entity = response.getEntity();
BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);
InputStream instream = bufHttpEntity.getContent();
Bitmap bm = BitmapFactory.decodeStream(instream);

출처: http://cafe.naver.com/busanandroid.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=96
블로그 이미지

By훈트

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

이번에는 Bitmap 데이터 형을 byte Array로 변환하거나 혹은 그 역으로 변환하는 예제를 다루어 보도록 하겠습니다.

해결책

ByteArrayOutputStream 인스턴스를 생성한 후, Bitmap의 compress 메서드를 통해 비트맵을 압축하여 stream에 담습니다.

BitmapFactory의 decodeByteArray 메서드를 통해 byte Array를 Bitmap으로 변환합니다.

토의

안드로이드의 Bitmap은 비트맵 데이터를 stream에 넣어주는 compress 메서드를 제공하고 있습니다.

  1. public byte[] bitmapToByteArray( Bitmap $bitmap ) {  
  2.         ByteArrayOutputStream stream = new ByteArrayOutputStream() ;  
  3.         $bitmap.compress( CompressFormat.JPEG, 100, stream) ;  
  4.         byte[] byteArray = stream.toByteArray() ;  
  5.         return byteArray ;  
  6.     }  

compress 인자 값에는 압축 옵션( JPEG, PNG ) 와 품질 설정 ( 0 - 100까지의 int형 ), 그리고 압축된 바이트배열을 담을 stream을 넘겨줍니다.

byteArray는 stream의 toByteArray() 메서드를 통해 반환받을 수 있습니다.

다음은 역으로, 바이트 배열로부터 비트맵을 생성하는 코드 입니다.

  1. public Bitmap byteArrayToBitmap( byte[] $byteArray ) {  
  2.     Bitmap bitmap = BitmapFactory.decodeByteArray( $byteArray, 0, $byteArray.length ) ;  
  3.     return bitmap ;  
  4. }  

바이트 배열로부터 비트맵 생성은 BitmapFactory의 decodeByteArray의 메서드를 통해 간단히 생성할 수 있습니다. decodeByteArray의 메서드 인자값으로 바이트 배열과 offset(배열의 시작점), length(decode할 바이트 배열의 길이)를 넘겨줍니다.

결과

관련예제

안드로이드 카메라 캡쳐해서 bitmap 얻어오기



[출처] 시스님의 블로그

블로그 이미지

By훈트

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

안드로이드에서 기본적으로 지원하지 않는 UI 를 만들때 CustomView 를 사용합니다.

이러한 CustomView 의 기본적인 작성방법을 알아보도록 하겠습니다.

 

CustomView 는 “android.view.View” 클래스를 상속해서 만들어 집니다.

기본적으로 onDraw() 메소드만 재정의해서 xml 에 view 태그만 추가하면 오류없이 출력되는것을 볼 수 있습니다.

 

이번 포스트에서는 간단히 클릭하면 반응하는 CustomView 를 만들어 보도록 하겠습니다.

먼저 CustomView 소스를 확인해 보도록 하겠습니다.

 

- CustomView.java

package net.cranix.android.customviewtest;

import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View;
public class CustomView extends View {
private String text = null; private int backgroundColor = Color.RED;
private String tempText;
// 속성이 없는 생성자는 소스상에서 직접 생성할때만 쓰인다. public CustomView(Context context) { super(context); Log.w(Constants.TAG,"CustomView("+context+")"); }
/* * 리소스 xml 파일에서 정의하면 이 생성자가 사용된다. * * 대부분 this 를 이용해 3번째 생성자로 넘기고 모든 처리를 3번째 생성자에서 한다. */ public CustomView(Context context,AttributeSet attrs) { this(context,attrs,0); Log.w(Constants.TAG,"CustomView("+context+","+attrs+")"); }

/* * xml 에서 넘어온 속성을 멤버변수로 셋팅하는 역할을 한다. */ public CustomView(Context context,AttributeSet attrs,int defStyle) { super(context,attrs,defStyle); this.text = attrs.getAttributeValue(null,"text"); Log.w(Constants.TAG,"CustomView("+context+","+attrs+","+defStyle+"),text:"+text); }

/* * xml 로 부터 모든 뷰를 inflate 를 끝내고 실행된다. * * 대부분 이 함수에서는 각종 변수 초기화가 이루어 진다. * * super 메소드에서는 아무것도 하지않기때문에 쓰지 않는다. */ @Override protected void onFinishInflate() { setClickable(true); Log.w(Constants.TAG,"onFinishInflate()"); }
/* * 넘어오는 파라메터는 부모뷰로부터 결정된 치수제한을 의미한다. * 또한 파라메터에는 bit 연산자를 사용해서 모드와 크기를 같이 담고있다. * 모드는 MeasureSpec.getMode(spec) 형태로 얻어오며 다음과 같은 3종류가 있다. * MeasureSpec.AT_MOST : wrap_content (뷰 내부의 크기에 따라 크기가 달라짐) * MeasureSpec.EXACTLY : fill_parent, match_parent (외부에서 이미 크기가 지정되었음) * MeasureSpec.UNSPECIFIED : MODE 가 셋팅되지 않은 크기가 넘어올때 (대부분 이 경우는 없다) * * fill_parent, match_parent 를 사용하면 윗단에서 이미 크기가 계산되어 EXACTLY 로 넘어온다. * 이러한 크기는 MeasureSpec.getSize(spec) 으로 얻어낼 수 있다. * * 이 메소드에서는 setMeasuredDimension(measuredWidth,measuredHeight) 를 호출해 주어야 하는데 * super.onMeasure() 에서는 기본으로 이를 기본으로 계산하는 함수를 포함하고 있다. * * 만약 xml 에서 크기를 wrap_content 로 설정했다면 이 함수에서 크기를 계산해서 셋팅해 줘야한다. * 그렇지 않으면 무조껀 fill_parent 로 나오게 된다. */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// height 진짜 크기 구하기 int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = 0; switch(heightMode) { case MeasureSpec.UNSPECIFIED://mode 가 셋팅되지 않은 크기가 넘어올때 heightSize = heightMeasureSpec; break; case MeasureSpec.AT_MOST://wrap_content (뷰 내부의 크기에 따라 크기가 달라짐) heightSize = 20; break; case MeasureSpec.EXACTLY://fill_parent, match_parent (외부에서 이미 크기가 지정되었음) heightSize = MeasureSpec.getSize(heightMeasureSpec); break; }
// width 진짜 크기 구하기 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = 0; switch(widthMode) { case MeasureSpec.UNSPECIFIED://mode 가 셋팅되지 않은 크기가 넘어올때 widthSize = widthMeasureSpec; break; case MeasureSpec.AT_MOST://wrap_content (뷰 내부의 크기에 따라 크기가 달라짐) widthSize = 100; break; case MeasureSpec.EXACTLY://fill_parent, match_parent (외부에서 이미 크기가 지정되었음) widthSize = MeasureSpec.getSize(widthMeasureSpec); break; }
Log.w(Constants.TAG,"onMeasure("+widthMeasureSpec+","+heightMeasureSpec+")"); setMeasuredDimension(widthSize, heightSize); }
/* * onMeasure() 메소드에서 결정된 width 와 height 을 가지고 어플리케이션 전체 화면에서 현재 뷰가 * 그려지는 bound 를 돌려준다. * 이 메소드에서는 일반적으로 이 뷰에 딸린 children 들을 위치시키고 크기를 조정하는 작업을 한다. * 유의할점은 넘어오는 파라메터가 어플리케이션 전체를 기준으로 위치를 돌려준다. * * super 메소드에서는 아무것도 하지않기때문에 쓰지 않는다. */ @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { Log.w(Constants.TAG,"onLayout("+changed+","+left+","+top+","+right+","+bottom+")"); }
/* * 이 뷰의 크기가 변경되었을때 호출된다. * * super 메소드에서는 아무것도 하지않기때문에 쓰지 않는다. */ @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { Log.w(Constants.TAG,"onSizeChanged("+w+","+h+","+oldw+","+oldh+")"); }
/* * 실제로 화면에 그리는 영역으로 View 를 상속하고 이 메소드만 구현해도 제대로 보여지게 된다. * * 그릴 위치는 0,0 으로 시작해서 getMeasuredWidth(), getMeasuredHeight() 까지 그리면 된다. * * super 메소드에서는 아무것도 하지않기때문에 쓰지 않는다. */ @Override protected void onDraw(Canvas canvas) { final Paint p = new Paint(); p.setColor(backgroundColor); canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(), p); if (text != null) { p.setColor(Color.BLACK); canvas.drawText(text, 10, 15, p); // 왼쪽 아래를 0,0 으로 보고있음 } Log.w(Constants.TAG,"onDraw("+canvas+")"); }
/* * 현재 view 가 focus 상태일때 key 를 누르면 이 메소드가 호출됨. * 즉 이 메소드를 사용하려면 setFocusable(true) 여야함. *
     * 그리고 super 메소드에서는 기본적인 키 작업(예를들면 BACK 키 누르면 종료)을 처리하기 때문에 
     * 일반적으로 return 시에 호출하는게 좋다.
     * 만약 기본적인 작업을 하지않게 하려면 super 함수를 호출하지 않아도 된다.
     * 
     * 다른 event 메소드들도 유사하게 동작한다.
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Log.w(Constants.TAG,"onKeyDown("+keyCode+","+event+")");
        return super.onKeyDown(keyCode, event); 
    }
/* * 이 view 에 touch 가 일어날때 실행됨. * * 기본적으로 touch up 이벤트가 일어날때만 잡아내며 * setClickable(true) 로 셋팅하면 up,move,down 모두 잡아냄 */ @Override public boolean onTouchEvent(MotionEvent event) { Log.w(Constants.TAG,"onTouchEvent("+event+")"); switch(event.getAction()) { case MotionEvent.ACTION_UP: backgroundColor = Color.RED; text = tempText; break; case MotionEvent.ACTION_DOWN: backgroundColor = Color.YELLOW; tempText = text; text = "Clicked!"; break; case MotionEvent.ACTION_MOVE: backgroundColor = Color.BLUE; text = "Moved!"; break; } invalidate(); return super.onTouchEvent(event); }
public String getText() { return text; }
public void setText(String text) { this.text = text; } }

- 크기 계산하기

여기서 중요한 메소드는 onMeasure() 메소드 입니다.

이 메소드는 뷰의 전체 크기를 정하는 메소드 인데 안드로이드의 크기 정하는 방법에 따라 구현법이 달라져야 합니다.

 

안드로이드 레이아웃 xml 파일에서 크기를 지정하는 방법은 4가지가 있습니다.

   - fill_parent (상위 View 의 크기에 따름)

   - match_parent (상위 View 의 크기에 따름)

   - fixed (100px 와 같이 픽셀로 박아놨을때)

   - wrap_content (현재 뷰의 내용에 따름)

 

이렇게 4가지 방법의 특성에 따라서 넘어오는 크기의 종류는 3가지로 구분됩니다.

   - MeasureSpec.EXACTLY : fill_parent, match_parent, fixed 와 같이 상위에서 이미 결정되어버린 크기가 넘어올때 선택됩니다.

   - MeasureSpec.AT_MOST : wrap_content 를 선택했을때 선택됩니다.

   - MeasureSpec.UNSPECIFIED : xml 에 의하지 않고 소스상에서 직접 넣었을 때 나옵니다.

 

여기서 EXACTLY 과 UNSPECIFIED 는 외부에서 크기가 구해져서 내려오는 것이기 때문에 따로 계산할 것이 없으나 AT_MOST 는 내부적으로 크기계산을 해 주어야 합니다.

위의 소스에서는 간단하게 100,20 으로 박아놨지만 실제로 CustomView 를 구현하게 된다면 뷰의 특성에 따라 구현이 달라져야 할 것입니다.

 

 

- xml 에서 파라메터 받아내기

안드로이드 리소스 xml 에서 파라메터를 받아내려면 위 소스의 3번째 생성자에 있는것 처럼 아래와 같은 구문을 써야 합니다.

this.text = attrs.getAttributeValue(null,"text");

 

 

- xml 파일 구성하기

이렇게 만든 CustomView 를 xml 파일에서 사용하려면 아래와같은 xml 구성이 필요합니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<view class="net.cranix.android.customviewtest.CustomView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
text="test"
/>
</LinearLayout>

 

- 실행해 보기

이렇게 구성된 뷰를 Activity 에 넣고 실행해 보면 아래와 같은 화면이 나옵니다.

마우스를 클릭,이동 할때마다 색깔이 변경되는것을 볼 수 있습니다.

image

image

image


[출처] 닉스로그님의 블로그


블로그 이미지

By훈트

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
1. Collection
  • Map은 key와 value를 가진 집합이며, 중복을 허용하지 않는다.
  • 즉, 한개의 key에 한개의 value가 매칭된다.
  • java.util 패키지에 여러 집합들을 사용하기 위한 여러 interface와 class 들이 정의되어 있다.
2. HashMap
  • HashMap은 Map interface를 implements 한 클래스로서 중복을 허용하지 않는다.
  • Map의 특징인 key와 value의 쌍으로 이루어지며, key 또는 value 값으로써 null을 허용한다.
  • 아래의 예는 HashMap을 사용한 간단한 예제이다.

    import java.util.*;

     

    public class HashMapTest
    {
        public static void main(String argv[])
        {
            HashMap hm = new HashMap();
            System.out.println(hm.put("aaa", "111"));
            System.out.println(hm.put("bbb", "222"));
            System.out.println(hm.put("aaa", "444"));
            System.out.println(hm.put("ccc", "333"));    
            System.out.println(hm.put("ccc", null));       
            
            System.out.println("HashMap size : " + hm.size());
            
            Set set = hm.keySet();
            Object []hmKeys = set.toArray();
            for(int i = 0; i < hmKeys.length; i++)
            {
                String key = (String)hmKeys[i];   
                System.out.print(key);
                System.out.print(" - ");
                System.out.println((String)hm.get(key));
            }
        }
    }


    /**
    실행:java HashMapTest
    결과:
    null
    null
    111
    null
    333
    HashMap size : 3
    ccc - null
    bbb - 222
    aaa - 444
    */

3. TreeMap
  • TreeMap역시 중복을 허용하지 않으며, key와 value의 쌍으로 이루어져 있다.
  • HashMap과 다른 점은 SortedMap을 implements 하였으므로, key 값들에 대한 정렬이 이루어진다는 점이다.
  • 아래의 예는 TreeMap을 사용하여 각 요소가 몇몇 이나 나왔는지 알아보는 간단한 예제이다.

    import java.util.*;

    public class Freq

    {
        private static final Integer ONE = new Integer(1);

        public static void main(String args[])

        {
            Map m = new TreeMap();

            // Initialize frequency table from command line
            for (int i=0; i < args.length; i++)

            {
                Integer freq = (Integer) m.get(args[i]);
                m.put(args[i], (freq==null ? ONE :
                                new Integer(freq.intValue() + 1)));
            }

            System.out.println(m.size()+" distinct words detected:");
            System.out.println(m);
        }
    }


    /**
    실행:java Freq if it is to be it is up to me to delegate
    결과:
    8 distinct words detected:
    {be=1, delegate=1, if=1, is=2, it=2, me=1, to=3, up=1}
    */

4. Hashtable
  • Hashtable Map interface를 implements 한 클래스로서 중복을 허용하지 않는다.
  • Map의 특징인 key와 value의 쌍으로 이루어지며, key 또는 value 값으로써 null을 허용하지 않는다.(HashMap과의 차이점)
  • 아래의 예는 HashTable을 사용한 간단한 예제이다.

    import java.util.*;

    public class HashtableTest

    {

        public static void main(String argv[])
        {
            Hashtable ht = new Hashtable();
            System.out.println(ht.put("aaa", "111"));
            System.out.println(ht.put("bbb", "222"));
            System.out.println(ht.put("aaa", "444"));
            System.out.println(ht.put("ccc", "333"));    
            
            System.out.println("Hashtable size : " + ht.size());
            
            System.out.println("aaa value : " + (String)ht.get("aaa");
            
        }
    }


    /**
    실행:java HashMapTest
    결과:
    null
    null
    111
    null
    Hashtable size : 3
    aaa value : 444
    */

블로그 이미지

By훈트

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

01./** Get Bitmap's Width **/
02.public static int getBitmapOfWidth( String fileName ){
03.try {
04.BitmapFactory.Options options = new BitmapFactory.Options();
05.options.inJustDecodeBounds = true;
06.BitmapFactory.decodeFile(fileName, options);
07.return options.outWidth;
08.catch(Exception e) {
09.return 0;
10.}
11.}
12. 
13./** Get Bitmap's height **/
14.public static int getBitmapOfHeight( String fileName ){
15. 
16.try {
17.BitmapFactory.Options options = new BitmapFactory.Options();
18.options.inJustDecodeBounds = true;
19.BitmapFactory.decodeFile(fileName, options);
20. 
21.return options.outHeight;
22.catch(Exception e) {
23.return 0;
24.}
25.}

[출처] 안드로이드펍 SSamDDak님의 답변

'Programming > Android' 카테고리의 다른 글

[Android] Bitmap, byte[] 간의 변환  (5) 2011.02.18
[Android] CustomView 만들기  (0) 2011.02.15
[Android] Screen Size  (0) 2011.01.26
[Android] LockableMessageHandler  (0) 2011.01.24
[Android] android:textAppearance 사용하기  (0) 2011.01.24
블로그 이미지

By훈트

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

출처 : http://penta82.egloos.com/4099869

 

JCF(Java Collection Framework)에서 많이 사용되었던 Hashtable에 대해서 살펴보자.

Hashtable은 JDK 1.2이전부터 존재해 왔던 클래스이다. 많은 사람들이 의문인 것은 왜 HashTable이 아니냐는 것인데 여기서는 그냥 넘어가자. 클래스명이야 소스 개발자의 몫이니까.

Hashtable의 중요 메소드를 살펴보면,

  • void clear()
    • 모든 키와 값을 제거한다.
  • boolean contains(Object value), containsValue(Object value)
    • 주어진 객체에 대응하는 키 값이 있는지 알려준다.
  • boolean containsKey(Object key)
    • 주어진 키 값이 있는지 알려준다.
  • Enumeration keys()
    • 해시 테이블의 키 값들을 돌려준다.
  • Enumeration elements()
    • 해시 테이블에 저장된 객체들을 돌려준다.
  • Object get(Object key)
    • 주어진 키에 대응하는 값을 돌려준다.
  • Object put(Object key, Object value)
    • 키와 대응하는 값을 저장한다.
  • Object remove(Object key)
    • 키의 대응 관계(Mapping)을 제거한다.
  • int size()
    • 해시 테이블의 대응 관계(Mapping)의 개수를 돌려준다.

여기서 'Enumeration이 무엇인가?' 하는 궁금증이 있을 것이다. Enumeration은 단순히 객체들의 목록을 가지고 있는 구조체라고 생각하면 된다. Enumeration클래스의 메소드를 보면

  • boolean hasMoreElements()
    • 더 이상의 요소가 있는지 알려준다.
  • nextElements()
    • 다음 요소를 돌려준다. 만약 없다면, NoSuchElementException 예외를 발생한다.

따라서 위의 두 메소드를 사용하면 for문, while문을 이용하지 않고도 key값과 element값에 접근할 수 있다.

이제 관련 소스를 살펴보자.

public class HashtableExam2 {
    
    public static void main(String[] args) {
        Hashtable htable = new Hashtable(10);
        
        // put(Object key, Object value)메소드
        htable.put("java", "프로그래밍 언어");
        htable.put("bible", "성서, 성경, 성전");
        htable.put("star", "별, 항성");
        htable.put("moon", "달");
        
        // contains(Object value);
        if(htable.contains("프로그래밍 언어")) {
            System.out.println("value : \"프로그래밍 언어\" 존재");
        }else{
            System.out.println("value : \"프로그래밍 언어\" 존재하지 않음");
        }    
        
        if(htable.contains("음악")) {
            System.out.println("value : \"음악\" 존재");
        }else{
            System.out.println("value : \"음악\" 존재하지 않음");
        }
        
        // containsValue(Object value)
        if(htable.containsValue("프로그래밍 언어")) {
            System.out.println("value : \"프로그래밍 언어\" 존재");
        }else{
            System.out.println("value : \"프로그래밍 언어\" 존재하지 않음");
        }
        
        if(htable.containsValue("음악")) {
            System.out.println("value : \"음악\" 존재");
        }else{
            System.out.println("value : \"음악\" 존재하지 않음");
        }
        
        // containsKey(Object key)
        if(htable.containsKey("java")) {
            System.out.println("key : \"java\" 존재");
        }else{
            System.out.println("key : \"java\" 존재하지 않음");
        }
        
        if(htable.containsValue("ruby")) {
            System.out.println("key : \"ruby\" 존재");
        }else{
            System.out.println("key : \"ruby\" 존재하지 않음");
        }
        
        // get(Object key)
        String value = (String)htable.get("java");
        System.out.println("java(key) : " + value + "(value)");
        
        // remove(Object key)
        htable.remove("star");
        
        // Enumeration 사용
        Enumeration e = htable.keys();
        String key, val;
        while(e.hasMoreElements()) {
            key = (String)e.nextElement();
            val = (String)htable.get(key);
            System.out.println("[" + key + "] " + val);
        }
        
        // clear()
        htable.clear();
        
        // size()
        System.out.println("htable의 size : " + htable.size());
    }

}
블로그 이미지

By훈트

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
블로그 이미지

By훈트

,