오늘은 어디로 갈까...

백수 2일째 본문

白手日誌

백수 2일째

剛宇 2009. 7. 2. 15:14

 오늘은 비가 오는 관계로, 작업을 중단하고, 멍하니~ 하늘만을 바라보고 있다. 마음같아서는 비를 맞으며, 거리를 걷고 싶지만, 뒷감당이 무서워서 그냥 참고 있다. 이름이 강우라서 비를 좋아하는것일까, 비를 좋아해서 강우가 된것일까... ^^;

 오늘 예정 작업은 DAMO의 캐시(Cache)부분이었다. (그렇다. 비가 오는 관계로 내일로 미루어졌다. --;)
 간단히 사용할것이면 메모리 캐시마냥 Map 하나  선언해놓고, 데이터를 마구 넣구, 마구 가져가기를 하면 되지만, 여러가지 제약사항과 다양한 기능을 사용하기 위해서 기존에 만들어진 것을 가져다 쓰기로 했다. 자바용 캐시는 의외로 많이 있지만 유명한 것들은 아래와 같다.
 



 여기서는 EHCache를 사용하기로 했다. 그 이유는 Fast & Simple 라고 스스로 말하고 있기 때문이다. ^^; 사용법은 그다지 어렵지 않으니 생략하고, 오늘은 약간 재밌는 상황(?)에 대해 알아보자.
 EHCache는 메모리와 디스크 두가지 모두 사용한다. 알아볼것은 메모리쪽인데, 1.6버젼에서 MemoryStore는 내부적으로 ConcurrentHashMap이란 HashMap의 친구를 사용한다. 문제는 이 HashMap이다. 너무 기본에 속해서 가끔 잊어버리곤 하는데, HashMap은 hash를 사용한다는 소리이다. --; 일단 아래 소스를 실행해보자.

package kr.kangwoo.damo;

import java.util.HashMap;
import java.util.Map;

public class TestHashMap {

	public static void main(String[] args) {
		Map<KeyObject, String> map = new HashMap<KeyObject, String>();
		KeyObject key = new KeyObject("Hello");
		KeyObject another = new KeyObject("Hello");
		map.put(key, "Hello Java");
		System.out.println(key.equals(another));
		System.out.println(map.get(key));
		System.out.println(map.get(another));
	}
	
	static class KeyObject {
		String key;
		KeyObject(String key) {
			this.key = key;
		}
		
		@Override
		public boolean equals(Object obj) {
			if (obj == null) {
				return false;
			}
			if (obj instanceof KeyObject) {
				KeyObject another = (KeyObject)obj;
				return (key != null ) ? key.equals(another.key) : (another.key == null);				
			}
			return false;
		}
		
		@Override
		public String toString() {
			return key;
		}
	}
}


아주 간단한 코드이다. 특정 객체를 만들어서 Map에다 넣어주는것이다. 실행해보면 뜻밖의(?) 결과가 나올것이다. --;
* 실행결과
true
Hello Java
null

Map의 get(key) 메소드를 사용하면 key와 동일한(equals) 키의 객체를 가져온다. 위에서 보다시피, key.equals(another)는 true 즉, 같은것이다. 그런데 map.get(another)의 값을 null이다. 어디가 잘못된 것일까? 사실 잘못된 곳은 없고 실수(?)가 있을 뿐이다. 이게 HashMap이 아니라 다른 종류의 Map이었다면 "Hello Java"라는 값을 가져올 수 있을것이다. 즉, HashMap이라서 null이 반환된것이다. 앞에서 얘기했던것처럼 HashMap은 hash를 사용한다. 뭔소리인고 하니, HashMap은 빠른 검색을 위해서 내부적으로 키 객체의 hashCode를 가져온다음, 같은 hashCode끼리 묶어놓고, get(key)요청이 오면 동일한 hashCode의 묶음내에서 동일한지(equlas)한지 판단한다는 것이다.
 그렇다면 map.get(another)가 "Hello Java"라는 값을 반환하도록 할려면 어떻게 변경해야할까? KeyObject 클래스의 hashCode() 메소드를 오버라이딩해주면 된다.
	static class KeyObject {
		String key;
		KeyObject(String key) {
			this.key = key;
		}
		
		@Override
		public boolean equals(Object obj) {
			if (obj == null) {
				return false;
			}
			KeyObject another = (KeyObject)obj;
			return (key != null ) ? key.equals(another.key) : (another.key == null);
		}
		
		@Override
		public int hashCode() {
			return (key != null) ? key.hashCode() : 0;
		}
		
		@Override
		public String toString() {
			return key;
		}
	}


 위에처럼 구현해주면 원하는(?) 결과를 얻을 수 있다.

* 실행결과
true
Hello Java
Hello Java


 흠흠. Damo에서 캐시를 사용할때 키(key)가 필요하다. 키를 EntityObject 그 자체로 쓰기 위해서는, EntityObject에 hashCode()와 equlas()메소들를 오버라이딩해줘야하는데, 그걸 개발자에게 요구한다는 것은 너무 가혹한 행위가 아닐까.....? 키(key)를 생생해내는 빠르고, 쉬운 방법을 한번 연구해봐야겠다 --;