java.util.AbstractMap은 자바에서 제공하는 추상 클래스 중 하나입니다. 이 클래스는 Map 인터페이스를 구현하는 클래스를 작성하는 데 사용됩니다.
Map은 key-value 쌍으로 데이터를 저장하는 자료구조입니다. 자바에서는 Map 인터페이스를 구현하는 여러 클래스들을 제공하며, AbstractMap은 이러한 클래스들을 작성할 때 기본이 되는 추상 클래스입니다. AbstractMap은 Map 인터페이스를 구현하기 위한 기본적인 메서드들을 이미 구현하고 있으므로, Map을 구현하는 클래스가 이 클래스를 상속받으면 Map 인터페이스를 구현하기 위한 일부 메서드를 더 쉽게 구현할 수 있습니다.
AbstractMap은 다음과 같은 메서드를 구현하고 있습니다:
- clear(): Map에 저장된 모든 key-value 쌍을 제거합니다.
- containsKey(Object key): 지정된 key가 Map에 존재하는지 여부를 반환합니다.
- containsValue(Object value): 지정된 value가 Map에 존재하는지 여부를 반환합니다.
- equals(Object o): 지정된 객체가 이 Map과 동일한 key-value 쌍을 가지고 있는지 여부를 반환합니다.
- get(Object key): 지정된 key에 대응하는 value를 반환합니다. 만약 key가 Map에 존재하지 않으면 null을 반환합니다.
- hashCode(): 이 Map의 해시 코드를 반환합니다.
- isEmpty(): 이 Map이 비어있는지 여부를 반환합니다.
- keySet(): 이 Map에 존재하는 모든 key를 Set으로 반환합니다.
- put(K key, V value): 지정된 key-value 쌍을 이 Map에 추가합니다. 만약 이미 해당 key가 Map에 존재하면, 이전 value가 새로운 value로 대체됩니다.
- putAll(Map<? extends K,? extends V> m): 지정된 Map의 모든 key-value 쌍을 이 Map에 추가합니다.
- remove(Object key): 지정된 key에 대응하는 key-value 쌍을 이 Map에서 제거합니다. 만약 key가 Map에 존재하지 않으면, 아무 일도 일어나지 않습니다.
- size(): 이 Map에 저장된 key-value 쌍의 수를 반환합니다.
- values(): 이 Map에 존재하는 모든 value를 Collection으로 반환합니다.
AbstractMap 클래스는 추상 클래스이기 때문에, 이 클래스를 직접 사용할 수는 없습니다. 대신 이 클래스를 상속받아 Map 인터페이스를 구현하는 클래스를 작성할 수 있습니다. 이 때, AbstractMap이 구현한 메서드들 중에서 구현할 필요가 없는 메서드들은 그대로 상속받아서 사용할 수 있으며, 구현할 필요가 있는 메서드들만 구현하면 됩니다.AbstractMap 클래스를 상속받아서 Map 인터페이스를 구현하는 클래스를 작성할 때는 다음과 같은 메서드를 구현해야 합니다:
- entrySet(): 이 Map에 저장된 모든 key-value 쌍을 Map.Entry 객체로 묶어서 Set으로 반환합니다.
- putIfAbsent(K key, V value): 지정된 key-value 쌍을 이 Map에 추가합니다. 만약 이미 해당 key가 Map에 존재하면, 이전 value가 반환됩니다. 만약 해당 key가 Map에 존재하지 않으면, 지정된 value가 Map에 추가되고 null이 반환됩니다.
- remove(Object key, Object value): 지정된 key-value 쌍이 Map에 존재하면 이를 제거합니다. 만약 key-value 쌍이 Map에 존재하지 않으면 아무 일도 일어나지 않습니다. 만약 key-value 쌍이 Map에 존재하고, 해당 key에 대응하는 value가 지정된 value와 일치하지 않으면 아무 일도 일어나지 않습니다.
- replace(K key, V oldValue, V newValue): 지정된 key에 대응하는 value가 oldValue와 일치하면, 해당 key에 대응하는 value를 newValue로 변경합니다. 만약 oldValue와 일치하는 key-value 쌍이 Map에 존재하지 않으면 아무 일도 일어나지 않습니다. 반환값은 oldValue와 일치하는 key-value 쌍이 Map에 존재하면, oldValue를 반환하고, 일치하는 key-value 쌍이 Map에 존재하지 않으면 null을 반환합니다.
- replace(K key, V value): 지정된 key에 대응하는 value를 newValue로 변경합니다. 만약 해당 key가 Map에 존재하지 않으면 아무 일도 일어나지 않습니다. 반환값은 해당 key에 대응하는 이전 value이며, 해당 key가 Map에 존재하지 않으면 null을 반환합니다.
AbstractMap 클래스를 상속받아서 Map 인터페이스를 구현하는 클래스를 작성할 때, 위의 메서드들을 구현함으로써 이 클래스를 사용하는 코드에서 Map 인터페이스의 다양한 메서드들을 사용할 수 있습니다. 또한, 이 클래스를 상속받는 클래스는 put() 메서드와 같은 기본적인 메서드들을 구현할 필요가 없기 때문에, 코드의 중복을 줄일 수 있습니다.
그러나 AbstractMap 클래스를 상속받아서 Map 인터페이스를 구현하는 클래스를 작성할 때는, entrySet() 메서드를 구현하는 것이 중요합니다. entrySet() 메서드는 Map 인터페이스의 많은 메서드들이 필요로 하는 Map.Entry 객체를 제공하기 때문에, 이 메서드를 구현하지 않으면 Map 인터페이스의 다양한 메서드들을 사용할 수 없습니다.다음은 AbstractMap 클래스를 상속받아서 Map 인터페이스를 구현한 간단한 예제 코드입니다.
import java.util.AbstractMap;
import java.util.Map;
import java.util.Set;
public class MyMap<K, V> extends AbstractMap<K, V> {
private Object[][] entries;
private int size;
public MyMap() {
entries = new Object[10][2];
size = 0;
}
@Override
public Set<Entry<K, V>> entrySet() {
Set<Entry<K, V>> set = new MySet<>();
for (int i = 0; i < size; i++) {
set.add(new MyEntry<>(entries[i][0], entries[i][1]));
}
return set;
}
@Override
public V put(K key, V value) {
for (int i = 0; i < size; i++) {
if (entries[i][0].equals(key)) {
V oldValue = (V) entries[i][1];
entries[i][1] = value;
return oldValue;
}
}
if (size >= entries.length) {
Object[][] newEntries = new Object[2 * entries.length][2];
System.arraycopy(entries, 0, newEntries, 0, entries.length);
entries = newEntries;
}
entries[size][0] = key;
entries[size][1] = value;
size++;
return null;
}
private class MySet<E> extends AbstractSet<Entry<K, V>> {
@Override
public Iterator<Entry<K, V>> iterator() {
return new MyIterator();
}
@Override
public int size() {
return size;
}
}
private class MyEntry<K, V> implements Entry<K, V> {
private K key;
private V value;
public MyEntry(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
}
private class MyIterator implements Iterator<Entry<K, V>> {
private int currentIndex = 0;
@Override
public boolean hasNext() {
return currentIndex < size;
}
@Override
public Entry<K, V> next() {
Entry<K, V> entry = new MyEntry<>((K) entries[currentIndex][0], (V) entries[currentIndex][1]);
currentIndex++;
return entry;
}
@Override
public void remove() {
for (int i = currentIndex; i < size - 1; i++) {
entries[i] = entries[i + 1];
}
entries[size - 1] = null;
size--;
}
}
}
위 코드에서 MyMap 클래스는 AbstractMap 클래스를 상속받아서 Map 인터페이스를 구현하고 있습니다. MyMap 클래스는 내부적으로 Object 타입의 2차원 배열을 사용하여 key-value 쌍을 저장하고 있습니다.
'PT선생님의 코딩 강좌' 카테고리의 다른 글
[PT선생님][33]java.util.AbstractMap.SimpleImmutableEntry 알아보기 (0) | 2023.02.24 |
---|---|
[PT선생님][32]java.util.AbstractMap.SimpleEntry 알아보기 (0) | 2023.02.24 |
[PT선생님][30]javax.swing.AbstractListModel 알아보기 (0) | 2023.02.23 |
[PT선생님][29]자바 java.util.AbstractList 알아보기 (0) | 2023.02.23 |
[PT선생님][28]자바 javax.swing.tree.AbstractLayoutCache.NodeDimensions 알아보기 (0) | 2023.02.23 |