본문 바로가기

Java/문법

17 - 4 장 Map<K,V> 컬렉션 인터페이스

1. Map<K,V> 컬랙션의 특징

 

- Map<K,V>는 별도의 인터페이스로 존재 

 

1)Key와 Value 한 쌍으로 데이터를 저장

 

-Key(키)와 Value(값)의 한쌍으로 데이터 저장

- 엔트리(entry) : 한쌍의 데이터 

-Map.Entry 타입으로 정의 

 

2)Key는 중복 저장 불가, Value 중복 가능

 

-데이터를 구분하는 기준이 Key 값이기 때문에 Key값은 중복될 수 없음

-Value값은 Key값으로 구분해 가져올 수 있으므로 중복 허용

(Key값이 다르면 Value값이 동일하다고 해도 구분 가능)

 

2. Map<K,V> 인터페이스의 주요 메서드 

 

구분 메서드명 기능
데이터 추가 put(K key, V value) 입력매개변수의 (Key,Vlaue)를 Map 객체에 추가
putAll(Map<?extends K, ? extends V)m 입력매개변수의 Map 객체를 통째로 추가
데이터 변경 replace(K key, V value) Key에 해당하는 값을 Value값으로 변경(old값 리턴)
(단, 해당 key가 없으면 null 리턴)
replace(K key, V oldValue, V newValue_ (key, oldValue)의 쌍을 갖는 엔트리에서 oldValue를 newValue로 변경
(단, 해당 엔트리가 없으면 false를 리턴)
데이터 정보 추출 get(Object key) 매개변수의 Key 값에 해당하는 oldValue를 리턴
containsKey(Object key) 매개변수의 Key값이 포함돼 있는지 여부 
containsValue(Object Value) 매개변수의 Value값이 포함돼 있는지 여부
KeySet() Map 데이터들 중 Key들만 뽑아 Set 객체로 리턴
entrySet() Map의 각 엔트리들을 Set 객체로 담아 리턴
size() Map에 포함된 엔트리의 개수
데이터 삭제 remove(Object Key) 입력매개변수의 Key를 갖는 엔트리 삭제
(단, 해당 Key가 없으면 아무런 동작을 하지 않음)
remove(Object key, Object value) 입력매개변수의 (key,value)를 갖는 엔트리 삭제 
(단, 해당 엔트리가 없으면 아무런 동작하지 않음)
clear() Map 객체 내의 모든 데이터 삭제 

 

3. HashMap<K,V>

 

-Key값의 중복을 허용하지 않음

-Key값의 중복 여부를 확인하는 메커니즘

 ->Key 객체의 hashCode() 값이 같고, equals() 메서드가 true를 리턴하면 같은 객체로 인식 

-Key값을 HashSet<E>로 구현한 Map<K,V>객체 

-입출력 순서는 동일하지 않을 수도 있음(HashSet<E>의 특성)

-초기 저장 용량의 기본값 16

 

- HashMap<K,V>의 주요 메서드 

 

1) 데이터 추가 

Map<Integer,String>hmap1 = new HashMap<Integer,String>();
//1.put(K key, V value)
hmap1.put(2,"나다라");
hmap1.put(1,"가나라");
hmap1.put(3,"다라마");
System.out.println(hMap1.toString()); //{1=가나다, 2=나다라, 3=다라마}

//2.putAll(<Map ? extends k,?extends V>m)
Map<Integer,String>hMap2 = new HashMap<Integer,String>();
hMap2.putAll(hMap1);
System.out.println(hMap2.toString()); //{1=가나다, 2=나다라, 3=다라마}

2) 데이터 변경

//3.replace(K key, V value)
hMap2.replace(1,"가가가");
hMap2.replace(4,"라라라"); //동작하지 않음
System.out.println(hMap2.toString()); //{1=가가가, 2=나나나, 3=다라마}

//4.replace(K key, V value,V oldValue, V newValue)
hMap2.replace(1,"가가가","나나나");
hMap2.replace(2,"다다다","라라라"); //동작하지 않음
System.out.println(hMap2.toString()); // {1=나나나, 2=나다라, 3=다라마}

 

 

3) 데이터 정보 추출

 - keySet() 메서드는 현재 저장돼 있는 엔트리 중 Key 값만을 Set<E>로 가져옴 

 - entrySet() 메서드는 Map<K,V>에 포함된 모든 엔트리를 set<E>으로 가져올 수 있음

  -> Set<E> 객체의 원소타입이 엔트리 

//5.V get(Object key)
System.out.println(hMap2.get(1)); //나나나
System.out.println(hMap2.get(2)); //나다라	
System.out.println(hMap2.get(3)); //다라마

//6.containsKey(Object key)
System.out.println(hMap2.containsKey(1)); //true
System.out.println(hMap2.containseKey(5)); //false

//7.containsValue(Object value)
System.out.println(hMap2.containsValue("나나나"); //true
System.out.println(hMap2.containsValue("다다다"); //false

//8.Set<K> KeySet()
System.out.println(keySet.toString()); //[1,2,3]

//9.Set<Map.Entry<K,V>>entrySet()
Set<Map.Entry<Integer,String>>entrySet = hMap2.entrySet(); 
System.out.println(entrySet);

//10.size()
System.out.println(hMap2.sizes()); //3

 

 

4) 데이터 삭제 

//11.remove(Object key)
hMap2.remove(1);
hMap2.remove(4); //동작하지 않음
System.out.println(hMap2.toString()); //{2=나다라, 3=다라마}

//12.remove(Object key, Object value)
hMap2.remove(2,"나다라");
hmap2.remove(3,"다다다"); //동작하지 않음
System.out.println(hMap2.toString()); //{3=다라마}

//13.clear()
hMap2.clear();
Sysetm.out.println(hMap2.toString()); //{}

 

5) HashMap<K,V>에서 Key의 중복 확인 메커니즘

 

 - equals() 메서드 오버라이딩

 -> 두 객체의 필드 값이 같을 때 true 리턴

 - hashCode() 메서드 오버라이딩

 -> 필드값을 기준으로 해시코드 생성

 

class C {
	int data;
    public C(int data) {
    	this.data =data;
        }
        //Override
        public boolean equals(Object obj) {
        	if(obj instanceof C) {
            	this.data = ((C)obj).data;
                return true;
             }
             return false;
        }
        //override
        public int hashCode() {
        	return Objects.hash(data);
        }
}

public class HashMapMachnism {
	public static void main(String[] args) {
    	Map<C,String>hashMap3 = new HashMap<>();
        C c1 = new C(3);
        C c2 = new C(3);
        System.out.println(c1 == c2);
        System.out.println(c1.equals(c2));
        System.out.println(c1.hashCode() + "," +c2.hashCode());
        hashMap3.put(c1, "첫 번째");
        hashMap3.put(c2, "두 번째");
        System.out.println(hashMap3.size()); //1
     }
}

 

4. Hashtable<K,V>

 

- HashMap<K,V>구현 클래스가 단일 쓰레드에 적합한 반면, Hashtable은 멀티 쓰레드에 안정성을 가짐

- 하나의 Map<K,V> 객체를 2개의 쓰레드가 동시에 접근할 떄 HashTable<K,V> 내부의 주요 메서드가 동기화 메서드로 구현돼 있으므로 멀티 쓰레드에서 안전하게 동작

Map<Integer,String> hTable1 = new Hashtable<Integer,String>();

 

5. LinkedHashMap<K,V>

 

- HashMap<K,V> 기본 특징 + 입력 데이터의 순서정보를 추가로 갖고 있는 컬렉션

- 저장 데이터를 출력하면 항상 입력된 순서대로 출력

- Key를 LinkedHashSet<E>로 관리 (HashMap<K,V>에서는 Key를 HashSet<E>로 관리)

Map<Integer,String>lhMap1 = new LinkedHashMap<Integer,String>();

 

6. TreeMap<K,V>

 

- Map<K,V>의 기본 기능 + 정렬 및 검색 기능이 추가된 컬렉션

- 입력 순서와 관계없이 데이터를 Key값의 크기 순으로 저장

- Key 객체는 크기 비교의 기준을 갖고 있어야 함

- ShorteMap와 NavigableMap을 상속

- TreeMap<K,V>로 선언해야 SortedMap<K,V>와 NavigableMap<K,V>에서 추가된 정렬 및 추가 메서드 호출 가능

 

//Map<K,V>로 객체 타입을 선언할때 
Map<Integer, String> treeMap = new TreeMap<Integer,String>();
treeMap. Map<K,V> 메서드만 사용 가능

//TreeMap<K,V>로 객체 타입을 선언할때
TreeMap<Integer,String> treeMap = new TreeMap<Integer,String>();
treeMap.Map<K,V> 메서드와 추가된 정렬/검색 메서드 사용 가능

 

- TreeMap<K,V>의 주요 메서드 

->TreeSet<E>와 비슷 

-> 데이터가 (Key,Value)쌍의 엔트리 형태로 저장되기 때문에 Key와 엔트리에 데잍를 검색하거나 추출하는 메서드가 포함

 

1) TreeMap<K,V>의 객체 생성 및 데이터 추가와 출력

TreeMap<Integer,String> treeMap = new TreeMap<Integer,String>();
for(int i=20; i>0; i-=2)
	treeMap.put(i,i+"번째 데이터"):
System.out.println(treeMap.toString()); //{2=2번째 데이터, 4=4번째 데이터,...,20=20번째 데이터}

 

2) 데이터 검색

 

-firstKey(),firstEntry()는 각각 첫 번째 검색 데이터의 Key값과 엔트리를 가져옴

-lastKey(),lastEntry()는 각각 마지막 검색 데이터의 Key값과 엔트리를 가져옴

-lowerKey(),lowerEntry()는 각각 입력된 매개변수보다 가장 작은 인접한 값 

-higherKey(),higherEntry()는 각각 입력된 매개변수보다 가장 큰 인접한 값 

//1.firstKey()
System.out.println(treeMap.firstKey()); //2
//2.firstEntry()
System.out.println(treeMap.firstEntry()); //2=2번째 데이터 

//3.lastKey()
System.out.println(treeMap.lastKey()); //20
//4.lastEntry()
System.out.println(treeMap.lastEntry()); //20=20번째 데이터 

//5.lowerKey(K key)
System.out.println(treeMap.lowerKey(11)); //10
System.out.println(treeMap.lowerKey(10)); //8

//6.higherKey(K key)
System.out.println(treeMap.higherKey(11)); //12
System.out.println(treeMap.higherKey(10)); //12

 

3) 데이터 꺼내기

 

 - pollFirstEntry(), pollLastEntry()는 각각 가장 작은 Key값의 엔트리와 가장 큰 Key값의 엔트리를 꺼내오는 메서드

  -> 실제 TreeMap<K,V> 객체에서 데이터를 꺼내기 떄문에 데이터의 개수는 꺼낸만큼 줄어듬

//7.pollFirstEntry()
System.out.println(treeMap.pollFirstEntry()); //2=2번째 데이터
System.out.println(treeMap.toString()); //{4=4번째 데이터, 6=6번째 데이터, ..., 20=20번째 데이터}

//8.pollLastEntry()
System.out.println(treeMap.pollLastEntry()); //20=20번째 데이터 
System.out.println(treeMap.toString()); //{4=4번째 데이터, 6=6번째 데이터, ..., 18=18번째 데이터}

 

4) 데이터 부분 집합(subMap)의 생성

 

//9.SortedMap<K,V> headMap(K toKey)
SortedMap<Integer,String> sortedMap = treeMap.headMap(8);
System.out.println(sortedMap); //{4=4번째 데이터, 6=6번째 데이터}

//10.NavigableMap<K,V> headMap(K toKey, boolean inclusive)
NavigableMap<Integer,Stirng>navigableMap = treeMap.headMap(8,true);
System.out.println(navigableMap); //{4=4번째 데이터, 6=6번째 데이터, 8=8번째 데이터}

//11.SortedMap<K,V> tailMap(K toKey)
sortedMap=treeMap.tailMap(14); 
System.out.println(sortedMap); //{14=14번째 데이터, 16=16번째 데이터, 18=18번째 데이터}

//12.NavigableMap<K,V> tailMap(K toKey, booelean inclusvie)
navigableMap=treeMap.tailMap(14,false); 
System.out.println(navigableMap); //{16=16번째 데이터, 18=18번째 데이터}

//13.SortedMap<K,V> subMap(K fromKey, K toKey)
sortedMap = treeMap.subMap(6,10);
System.out.println(sortedMap); //{6=6번째 데이터, 8=8번째 데이터}

//14.NavigableMap<K,V> subMap(K fromKey, booelan frominclusive, K toKey, boolean toinclusive)
navigableMap = treeMap.subMap(6,false,10,true);
System.out.println(navigableMap); //{8=8번째 데이터, 10=10번째 데이터}

 

5) 데이터 정렬

 

//15.NavigableSet<K> descendingKeySet()
NavigableSet<Integer> navigableSet = treeMap.descendingKeySet();
System.out.println(navigableSet); //[18,16,14,...,4]
System.out.println(navigableSet.descendingSet()); //[4,6,8,...,18]

//16.NavigableMap<K,V> descendingMap()
System.out.println(navigableMap); //{18=18번째 데이터, 16=16번째 데이터,..,4=4번째 데이터}
System.out.println(navigableMap.descendingMap()); //{4=4번째 데이터, 6=6번째 데이터,..,18=18번째 데이터}

 

6) 사용자 클래스의 크기 비교 기준 제공

 

-Key값의 크기를 비교해 정렬 수행

 

-1) Comparable<T> 제네릭 인터페이스 구현

class MyComparableClass implements Comparable<MyComparableClass> {
	int data1;
    int data2;
    public MyComparableClass(int data1, int data2) {
    	this.data1 = data1;
        this.data2 = data2;
    }
    //크기 비교의 기준 설정
    //Override
    public int compareTo(MyComparableClass o) {
    	if(this.data1 < o.data1) return -1;
        else if(this.data1 == o.data1) retrun 0;
        else return 1;
    }
    //Override
    public String toString() {
    	return "data1="+data1+"을 갖고 있는 클래스";
    }
}

- 2) TreeMap<K,V> 객체를 생성하면서 Compartor<T>객체 제공

TreeMap<MyClass,String> treeMap5 = new TreeMap<MyClass, String>(new Comparator<MyClass<() {
	//override
    public int compare(MyClass o1, MyClass o2) {
    	if(o1.data1 < o2.data1) return -1;
        else if(o1.data1 == o2.data1) return 0;
        else return 1;
    }
});