Notice
Recent Posts
Recent Comments
Link
«   2025/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
Archives
Today
Total
관리 메뉴

우주코딩

List와 Set, HashSet, HashMap 본문

자바 본 강의

List와 Set, HashSet, HashMap

우주코딩 2021. 8. 26. 23:22

List와 Set

Iterable iterator() , forEach()
Collection add(), remove(), size(), isEmpty(), contain(), toArray()

List get(), indexOf(), set()
Set copyOf()

HashSet

HashSet (= 해시값을 가지고 방 배정을 한다)은 내부적으로 값을 저장할 때 위치 정보를 순서대로 저장하지 않는다.

add() 로 저장해서 hashCode() 리턴 받음
해시 값을 가지고 저장할 방의 위치를 결정

 

이미 hashCode() equals() 의 결과값이 같은 객체가 있기 때문에 중복저장하지 않는다.

ArrayList와 HastSet

ArrayList는 한줄에 매달려 있다.

HashSet은 여러 줄에 매단다.
이 때 ArrayList 의 매다는 위치 정보는 인덱스

HashSet의 매다는 위치 정보는 해시값을 쓴다.

 

저장한 순서대로 꺼낼 수 없기 때문에 index를 이용하여 값을 꺼낼 수 없다.
set.get(0); //<== 이런 메서드가 없다.

값을 꺼내는 방법

  1. HashSet에 들어있는 값을 배열로 받아 사용한다.
  2. 창고에서 값을 꺼내주는 전문가에게 도움을 받는다.
  • HashSet에서 값을 꺼내주는 일을 하는 도우미 객체를 얻는다.

Iterator 컬렉션에서값을꺼내주는객체 = set.iterator();

사용자 정의 데이터와 HashSet

static class Member {
String name;
int age;

public Member(String name, int age) {
this.name = name;
this.age = age;
}

Member v1 = new Member("홍길동", 20);
Member v2 = new Member("임꺽정", 30);
Member v3 = new Member("유관순", 16);
Member v4 = new Member("안중근", 20);
Member v5 = new Member("유관순", 16);

HashSet<Member> set = new HashSet<>();
set.add(v1);
set.add(v2);
set.add(v3);
set.add(v4);

set.add(v5);

기대? v3와 같은 값이기 때문에 저장되지 않을 것이다!

출력해보면 "유관순, 16" 데이터가 중복해서 저장되었음을 알 수 있다.

  • HashSet이 중복여부를 검사할 때 hashCode()와 equals()의 리턴값으로 판단한다.
  • Member 클래스에서 hashCode()와 equals()를 오버라이딩 하지 않았기 때문에 Object로부터 상속 받은 hashCode()와 equals()를 그대로 사용하였고, Object의 hashCode()는 인스턴스가 다르면 무조건 다른 해시값을 리턴한다.
    Object의 equals()는 인스턴스의 주소가 같은 지 검사한다.
  • 그래서 "유관순,16" 데이터가 같더라도 인스턴스가 다르기 때문에 같은 값으로 간주하지 않은 것이다.

equals() , hashCode() 가 모두 같아야 같은 데이터로 인식한다.

HashMap

위치를 지정해서 값을 저장한다.
put(key,value) : 맵에 값 저장하기

  • key 객체에 대해 hashCode()를 호출하여 정수 값을 얻는다.
  • 이 해시값을 가지고 저장할 위치를 결정한다.

map.put("s01", new Member("홍길동", 20));

1) "s01" String 객체에 대해 hashCode()를 호출하여 해시 값을 얻는다.
2) 그 해시 값을 사용하여 저장할 위치를 결정한다.
3) 해당 위치에 Member 객체(의 주소)를 저장한다.

이전에 저장할 때 사용한 같은 키로 다른 값을 저장하면 기존 값을 덮어쓴다.

get(key) : 맵에서 값 꺼내기

  • 저장할 때 사용한 키를 가지고 꺼낸다.
  • System.out.println(map.get("s01"));

1) key 객체에 대해 hashCode()를 호출한다.
2) hashCode()의 리턴 값을 가지고 데이터를 찾을 위치를 결정한다.
3) 해당 위치에 있는 key 객체에 대해 equals()를 호출하여 리턴값을 확인한다.
4) equals()의 리턴 값이 true라면 같은 key로 간주하여 해당 위치의 값을 꺼낸다.

존재하지 않는 key를 지정하면 null을 리턴한다.


System.out.println(map.get("s05")); // null

 

  • 값을 저장할 때, key 객체의 hashCode() 리턴 값으로 위치를 계산하여 저장한다.
  • 값을 꺼낼 때, key 객체의 equals()의 리턴 값으로 같은 Key 인지 검사한다. key 객체의 hashCode() 리턴 값으로 위치를 계산한다.
  • 따라서 hashCode()의 리턴 값과 equals()의 비교 결과가 다르다고 나오면 같은 key가 아니기 때문에 값을 꺼낼 수 없다.
  • 우리가 사용한 MyKey 클래스는 hashCode()와 equals()를 오버라이딩 하지 않았기 때문에, 인스턴스 필드의 값이 같더라도 인스턴스가 다르면 hashCode()의 리턴 값이 다르게 나온다.equals() 또한 false를 리턴한다.

해결책?

  • 인스턴스가 다르더라도 인스턴스 필드의 값이 같을 때는 hashCode()의 리턴 값이 같게 오버라이딩 하라!
    또한 equals()의 리턴 값이 true가 되게 오버라이딩 하라!

hashCode() 와 equals() 를 모두 오버라이딩 해야 필드값 비교를 제대로 할 수 있다!

결론
HashMap의 key 객체로 사용할 클래스는 반드시 hashCode()와 equals()를 오버라이딩 하여 같은 값을 갖는 경우 같은 해시 값을 리턴하게 하라!

  • 개발자가 만든 클래스를 key 객체로 사용하려면 이런 번거로움이 있다.
  • 대부분 현업에서는 그냥 String을 key로 사용한다. 또는 Wrapper 클래스인 Integer를 사용하기도 한다.

HashMap keySet(), values(), entrySet()

HashMap과 Iterator

HashMap<String,Member> map = new HashMap<>();
map.put("s01", new Member("홍길동", 20));
map.put("s02", new Member("임꺽정", 30));
map.put("s03", new Member("유관순", 16));
map.put("s04", new Member("안중근", 20));
map.put("s05", new Member("윤봉길", 30));

java.util.Set<String> keys = map.keySet();

// Set 객체를 통해 key 를 꺼낼 때, 즉 keySet()을 호출할 때 모든 key를 미리 목록을 만들어 리턴하지 않는다.
// 그 순간의 HashSet에 있는 key를 꺼낸다.

Iterator<String> 키를꺼내주는객체 = keys.iterator();

// Iterator를 얻은 후에 새 값을 넣기
map.put("s06", new Member("김구", 50));

// Iterator 객체를 생성할 때, 현재 목록 객체(keys)를 바탕으로 생성한다.
// 따라서 Iterator를 생성한 후에 목록의 값을 변경하면, 기존 목록에서 뽑은 Iterator는 무효한 객체가 된다.

map.put("s06", new Member("김구", 50));
map.remove("s01");

// 해결책
// - 값을 변경하면 다시 Iterator를 얻어야 한다.
//    키를꺼내주는객체 = keys.iterator();

// 무효한 Iterator를 사용하면 실행오류가 발생할 것이다.
while (키를꺼내주는객체.hasNext()) {
    System.out.println(키를꺼내주는객체.next());
    }
  }

List vs Set vs Map

항목                   List      Set                        Map

1) 중복 저장       | 가능 | 불가능         | key 불가능, value 가능
2) null 허용 여부 | 가능 | 가능(한 개만) | HashMap(key/value 가능),
                                                  | Hashtable(key/value 불가능)

'자바 본 강의' 카테고리의 다른 글

File 입출력 클래스  (0) 2021.09.10
예외처리하기 Exception  (0) 2021.09.01
인터페이스 정리, Stack 클래스, Stack과 Deque  (0) 2021.08.26
람다 문법  (0) 2021.08.25
자바 API : ArrayList에 대해  (0) 2021.08.23
Comments