티스토리 뷰

Java/Class

10. Collections Framework : Map

알 수 없는 사용자 2018. 10. 31. 02:38


이번 포스팅에서는

Collections Framework에서 

따로 분류되어 있는

Map 인터페이스에 대해서 

알아보도록 하겠습니다.


===============================================


Collections Framework : Map





1. Map : What?

 

 Map 인터페이스로 구현된 클래스들은 Collection 클래스들과 다른 특성을 가지고 있습니다.

Map은 기본적으로 key 값과 value 값을 따로 가집니다. 이 때 value 값이 실제 넣고자 하는 객체가 들어가는 것이고 key 값은 해당 객체 값에 부여되어 value 값을 지칭하는 것입니다.

 배열과 비교한다면 key 값이 index, value 값이 실제 객체 데이터로 비교할 수 있습니다.





배열은 데이터를 순차적으로 저장하면서 int형의 index 값이 데이터를 참조할 수 있는 값으로 주어집니다.

그에 비해 Map은 사용자가 데이터를 저장하면서 index 값을 원하는 타입과 원하는 값으로 지정할 수 있습니다.

위 그림과 같이 First라는 key 값으로 데이터를 저장했다면, First에 속해있는 데이터를 얻을 수 있습니다.


여기서 key 값은 index의 역할과 비슷하기 때문에 당연히 중복되는 값이 올 수 없습니다. 그에 비해 value 값은 key 값에 속해, 관리하고자 하는 data이기 때문에 중복된 데이터가 올 수 있습니다.

만약 같은 key 값의 데이터를 저장하고자 한다면 기존에 존재하던 value 값 대신 새로 추가를 시도한 value 값이 해당 key의 value 값에 남게 됩니다.




[Map 인터페이스의 메서드]



Map 인터페이스는 비교적 많은 메서드를 가지고 있습니다. 

Map을 사용하면서 대게 많이 사용되는 메서드만 다루겠습니다.



- containsKey() / containsValue() : 인자로 전달하는 key / value 객체가 Map에 존재하는지 확인합니다.

- get() : 인자로 전달되는 key 값이 가진 value 값을 반환합니다.

- isEmpty() : Map 객체가 비어있는지 확인합니다.

- keySet() : Map 객체에 저장되어 있는 모든 key 값을 Set collection의 형태로 반환합니다.

- put() : 인자로 전달하는 key 값과 value 값을 연결하여 Map 객체에 저장합니다.

- remove() : 인자로 전달하는 key 값과 그에 대응하는 value 값을 삭제합니다.

- values() : Map에 존재하는 모든 value 값을 Collection 타입으로 반환합니다.

- entrySet() : Map에 저장된 key-value 쌍을 Map.Entry 객체의 타입으로 저장한 Set으로 반환합니다.



Map 인터페이스에 설계된 메소드의 특이한 점은 values() 메소드의 반환 타입은 Collection, keySet() 메소드의 반환 타입은 Set이라는 것입니다.

각 메소드의 반환 타입은 중복에 있습니다. 

keySet()은 저장된 모든 key 값을 가져오는 것으로 key 값은 중복될 수 없기 때문에 Set 타입으로 반환하고, value는 중복을 허용하기 때문에 Collection 타입으로 반환합니다.






2. Map : Map.Entry?



 Entry 인터페이스는 Map에 내부 인터페이스로 설계되어 있습니다. 

Map은 독특하게 key-value 쌍으로 데이터를 관리하는데 이 쌍을 하나의 객체, Entry로 만들어 보다 객체지향적으로 설계하도록 유도했습니다.


public interface Map {
...
interface Entry {
Object getKey();

Object getValue();

Object setValue(Object value);

boolean equals(Object o);

int hashCode();
...
}
}







3. Map : HashMap?


 Map 인터페이스를 구현하여 만들어진 클래스 중에서 가장 많이 쓰이는 클래스는 HashMap 클래스입니다.

HashMap은 Vector와 ArrayList의 관계처럼 Hashtable을 개선하여 만든 클래스입니다.


 장점으로는 순서대로 저장하는 것이 아니라 임의대로 저장하기 때문에, 특정 객체를 뽑아서 사용할 때 효율이 좋습니다. 또한 해싱을 사용하기 때문에 많은 양의 데이터를 검색하는 데 있어서 뛰어납니다.

 


public class HashMap extends AbstractMap implements Map, Cloneable, Serializable {
transient Entry[] table;
...
static class Entry implements Map.Entry {
final Object key;
Object value;
...
}
}

[HashMap의 데이터 관리, 자바의 정석 참고]



 HashMap은 내부 클래스로 Entry를 만들어 데이터를 관리합니다. 

value와 key값을 각각의 배열로 클래스 내부의 변수에서 사용하는 것이 아니라 Entry를 이용하여 관리합니다.

이는 데이터의 무결성적인 측면에서 더 바람직하기 때문에 다음과 같이 사용됩니다.


또한 key와 value 값은 모두 Object 형이기 때문에 어떠한 타입으로든 데이터를 관리할 수 있습니다. 하지만 key 값은 보통 String의 형태로 사용하는 것이 일반적입니다.




[HashMap의 메서드]


Map 인터페이스에 정의된 메서드와 거의 비슷합니다.






4. Map : TreeMap?


TreeMap은 TreeSet에서 본 Tree의 성질과 같습니다. 이진검색트리의 형태로 key와 value의 쌍으로 이루어진 데이터를 관리합니다. 그렇기 때문에 검색과 정렬에 적합한 클래스입니다. 다만 HashMap과 TreeMap의 성능 비교는 검색 면에서는 HashMap이 좋지만 범위검색이나 정렬에서는 TreeMap이 좋습니다.



[TreeMap 클래스의 메서드]





5. Map : Properties?


 Hashtable을 상속받아 구현한 Properties는 key와 value가 (String, String)의 형태로 저장되는 단순화된 클래스입니다.

주로 어플리케이션의 환경설정과 관련된 속성을 저장하는 데 사용되며 데이터를 파일로부터 읽고 쓰는 편리한 기능을 제공합니다.



[Properties의 메서드]






6. Map : How?



 Map계열의 클래스들은 다른 Collection들과는 달리 key와 value에 대한 타입을 제너릭으로 반드시 지정해주어야 합니다.

Map<String, String[]> map = new HashdMap<>(); // 객체 생성시 타입설정 조건 두가지 1. 저장할 객체 타입 2. 키로 쓸 객체타입
                                                // <키값의 타입, 저장할 객체 타입(배열형태)>


첫 번째 인자로 오는 타입이 key의 타입이고, 두 번째로 오는 타입이 value의 타입입니다.


또한 Entry 객체를 사용할 때도 Map 객체의 key-value의 타입은 곧 Entry이므로 Entry의 제너릭 타입을 Map과 일치시켜주어야 합니다.


public class Source14_Map {
public static void main(String[] args) {
Map<String, String[]> map = new HashdMap<>(); // 객체 생성시 타입설정 조건 두가지 1. 저장할 객체 타입 2. 키로 쓸 객체타입
                                                       // <키값의 타입, 저장할 객체 타입(배열형태)>

System.out.println(map.size()); // 0 / 관리중인 객체 사이즈
        System.out.println(map.isEmpty());    // true / 객체의 비어있는 상태 체크

        String[] a = "하준,도윤,시윤,시우,민준".split(",");
map.put("f", a); // (첫 번째 인자는 키값, 두 번째 인자는 저장 객체) map에 저장
        map.put("F", a); // 대문자 상관없음.
System.out.println(map.size()); // 2

String[] got = map.get("f"); // 키값에 대한 객체가 전달된다.
for(int i=0; i<got.length;i++) {
System.out.println(got[i]); // 하준, 도윤, 시윤, 시우, 민준
}

map.remove("f"); // 키값에 대한 객체 삭제, 키값을 모르면 객체를 제어할 방법이 없다.

// Map이 가지고있는 키값이 없더라도 에러가 발생하진 않음.
map.get("f"); // 해당 키값에 대한 객체가 없으면 null 반환

        String[] b = "서연,하연,지우".split(",");
map.put("F", b); // 같은 키가 사용되면 덮어씌움
        String[] got2 = map.get("F");
System.out.println(got2[0]); // 서연

        map.clear(); // 저장된 모든 객체 삭제
        System.out.println(map.size()); // 0
}
}


public class Source15_Map {
public static void main(String[] args) {
Map<Integer, String[]> map = new HashMap<>();

map.put(2, new String[] {"","","","two",""});
map.put(5, new String[] {"","다섯","","five",""});
map.put(3, new String[] {"","","","three","さん"});
map.put(4, new String[] {"","","","four",""});


        // put을 할 때 원래 키 값을 사용하던 객체가 있으면 기존에 존재하는 객체가 반환되지만 없었으면 null이 반환
        // remove 시에도 키값이 있던 객체를 삭제하면 삭제된 객체가 반환되고 키값이 없으면 null 반환
        // get도 마찬가지.

String[] obt = map.get(4);
for(String m : obt) {
System.out.println(m);
}

// containsKey()로 특정키가 사용되고 있는지 확인할 수 있음.
// put 하기전에 체크해서 없으면 새로 객체 생성, 있으면 덮어씌우기
        // get 하기전에 체크해서 없으면 등록객체 없는 것이고, 있으면 객체 반환
        // remove 하기전에 체크해서 없으면 삭제할 키값이 없는 것이고, 있으면 삭제 후 객체 반환
        // containsKey() Map의 종류에 따라 객체값이 달라도 동일 객체로 판단할 수 있음.
System.out.println(map.containsKey(2)); // true

// containsValue()
// equals 구현에 따라 바꿀 수도 있음.
System.out.println(map.containsValue(new String[] {"","","","two",""})); // false

// 새로운 String인스턴스 생성이기 때문

        // Map의 모든 객체를 확인하고 싶을 때는 keySet()으로 Key값을 얻어낸다.
// Map의 종류에 따라 정렬이 다르기 때문에 얻어지는 key정렬도 달라진다.
Set<Integer> k = map.keySet();
System.out.println(k); // [2, 3, 4, 5]
for(Integer i : k) { // for(Integer i : map.keySet()) {
System.out.println(i); // 2,3,4,5
}

// 어떤 키가 사용되고 있는지 몰라도 되고 특정 객체만 알고 시다면 values() 메소드를 사용
        Collection<String[]> c = map.values(); // Collection 최상위 객체로 반환
        for(String[] s : c) { // for(String[] s : map.values()) {
System.out.println(s);
}

System.out.println(map.toString()); // {2=[Ljava.lang.String;@15db9742, 3=[Ljava.lang.String;@6d06d69c ...

// entrySet()
// Entry의 제네릭 설정은 Map이랑 같게하면 된다.
// 키와 키에 해당하는 객체를 하나의 Entry 객체로 만들어 Set에 저장
        Set<Entry<Integer,String[]>> eset = map.entrySet();
for(Entry<Integer,String[]> e : eset) {
System.out.println(e);
System.out.println(e.getKey()); // Entry에서 key value를 뽑아냄
System.out.println(e.getValue());
}



}
}



'Java > Class' 카테고리의 다른 글

12. Thread : 쓰레드  (16) 2018.11.14
11. Collections Framework : 객체 비교  (0) 2018.11.04
9. Collections Framework : Queue, Deque  (0) 2018.10.30
8. Collections Framework : List  (0) 2018.10.29
7. Collections Framework : Set  (0) 2018.10.25
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함