Enumeration 클래스는 직접 인스턴스를 생성할 수 없지요..
그래서 Vector 라든가 Hashtable이라든가… 하는 객체들의 elements 나 keys 등의 메소드를 통해서 리턴받게 되죠..
실제 Enumeration 인터페이스를 구현한 인스턴스는 보통 해당 클래스의 서브 클래스로 구현되어 있습니다.
Hashtable을 예로 들자면 서브 클래스로
1 2 3 |
private class Enumerator implements Enumeration, Iterator { .... } |
요런 넘이 있습니다.
저 서브 클래스 내에 Enumeration 클래스에 정의되어있는
1 2 |
public boolean hasMoreElements(); public Object nextElement(); |
요 두가지가 구현되어있습니다.
Enumeration에는 두가지만 있지만 Iterrator 에는 몇가지가 더 있어서…
실제로 구현된 메소드는 몇가지가 더 있습니다.
위와 같이 구현된 메소드를 통해서 리턴받은 Enumeration 객체에서 위의 두 메소드를 사용할 수 있는 것이지요..
그럼.. 왜 그렇게 해야하느냐…
백터와 해시테이블 등등 Enumeration 인터페이스를 구현해놓은 클래스들은 데이터를 관리하는 내부 알고리즘이 다들 틀립니다.
하지만 사용하는 입장에서는 내부 알고리즘이야 어떻든지간에 꺼내서 보고 싶은거만 보면 그뿐인거죠..
해시테이블에서 전체 키값을 가져오는거하고..
백터에서 전체 리스트를 가져오는거하고 하는 일은 틀리지만 어쨌든 리스트를 돌려주니까…
사용하는 사람들 편하게 인터페이스를 통일해주는겁니다.
참 편리한 개념이지요..
쓰는 사람은 그냥 똑같은 인터페이스를 이용해서 필요한 정보를 취한다…
누가 어떻게 내부를 구현했는지 관심가질 필요가 없습니다.
해당 클래스에서 Enumeration 클래스가 구현되어있으면 그걸 그냥 쓰면 되는거죠.. ^^
참고로….
api에서도… Enumeration 보다는 Iterator를 쓰길 권합니다.
Iterator 에는 hasNext(), next(), remove() 요렇게 세개의 메소드가 정의되어 있습니다.
Enumeration 보다 하나 더 추가되었죠.. remove()…
그리고~ 메소드명도 간결해져서 타이핑도 줄여줍니다. ㅋㅋㅋ
아무튼 Enumeration 보다는 Iterator를 쓰시구요…
구현은 해당 클래스 내부에서 다 구현되어있으니 굳이 신경쓰지 않으시고 사용하시면 되겠습니다. ^^
저도 util package를 배울때 같은 고민을 한 적이 있어서 많은 공감이 갑니다 ^^
분명히 인터페이스고. 구현된 클래스도 없는데 어떻게 저렇게 돌아가지..??
source 를 까 뒤집다보면 튀어나오더군요.
어떤 메소드를 통해 Enumeration 을 반환하는 클래스의 경우 거의
익명클래스나 내부 클래스로 Enumeration을 구현한 클래스를 가지고 있습니다.
Hashtable의 경우를 보면 내부 클래스로 Enumerator 라는 클래스를 가지고 있습니다.
소스는 밑에 적어놓았습니다.
각 클래스들마다 자료 구조 모양은 다른데 똑같은 방식으로 안의 내용들을 보고 싶다… 그럴때 이렇게 각 자료구조마다 알맞게 구현된 Enumeration 을 접근할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
private class Enumerator implements Enumeration, Iterator { Entry[] table = Hashtable.this.table; int index = table.length; Entry entry = null; Entry lastReturned = null; int type; /** * Indicates whether this Enumerator is serving as an Iterator * or an Enumeration. (true -> Iterator). */ boolean iterator; /** * The modCount value that the iterator believes that the backing * List should have. If this expectation is violated, the iterator * has detected concurrent modification. */ protected int expectedModCount = modCount; Enumerator(int type, boolean iterator) { this.type = type; this.iterator = iterator; } public boolean hasMoreElements() { Entry e = entry; int i = index; Entry t[] = table; /* Use locals for faster loop iteration */ while (e == null && i > 0) { e = t[--i]; } entry = e; index = i; return e != null; } public Object nextElement() { Entry et = entry; int i = index; Entry t[] = table; /* Use locals for faster loop iteration */ while (et == null && i > 0) { et = t[--i]; } entry = et; index = i; if (et != null) { Entry e = lastReturned = entry; entry = e.next; return type == KEYS ? e.key : (type == VALUES ? e.value : e); } throw new NoSuchElementException("Hashtable Enumerator"); } // Iterator methods public boolean hasNext() { return hasMoreElements(); } public Object next() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); return nextElement(); } public void remove() { if (!iterator) throw new UnsupportedOperationException(); if (lastReturned == null) throw new IllegalStateException("Hashtable Enumerator"); if (modCount != expectedModCount) throw new ConcurrentModificationException(); synchronized(Hashtable.this) { Entry[] tab = Hashtable.this.table; int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index], prev = null; e != null; prev = e, e = e.next) { if (e == lastReturned) { modCount++; expectedModCount++; if (prev == null) tab[index] = e.next; else prev.next = e.next; count--; lastReturned = null; return; } } throw new ConcurrentModificationException(); } } } |