본문 바로가기

JAVA

[ JAVA ] 컬렉션 프레임워크 - List, Set, Map

 

 

컬렉션 프레임워크

 

자바가 자료구조(Data Structure)를 사용해서 객체들을 효율적으로 추가, 삭제, 검색할 수 있도록 인터페이스와 구현 클래스를 java.util 패키지에서 제공하는 것.

 

+ 컬렉션은 객체의 저장을 프레임워크란 사용 방법을 정해놓은 라이브러리를 말한다. 컬렉션 프레임워크의 주요 인터페이스로는 List, Set, Map이 있다. 이 인터페이스들은 컬렉션클래스를 사용하는 방법을 정의한 것이다. 

 

 

 

List 컬렉션

 

  • 배열과 비슷하게 객체를 인덱스로 관리한다.
  • 배열과 차이점은 저장 용량이 자동으로 증가하며 객체를 저장할 때 자동 인덱스가 부여된다는 것이다. 또한 추가, 삭제, 검색을 위한 다양한 메소드를 제공한다.
  • List 컬렉션은 객체 자체를 저장하는 것이 아니라 객체의 번지를 참조한다. 그렇기에 동일한 객체를 중복 저장할 수 있고 그럴 경우 동일한 번지가 참조 된다.
  • null 도 저장이 가능하고 null 일 경우 해당 인덱스는 객체를 참조하지 않는다.
  • List 컬렉션에는 ArrayList, Vector, LinkedList 등이 있고, 인덱스로 객체를 관리하기 때문에 인덱스를 매개값으로 같는 메소드가 많다.
List<String> list = new ArrayList<String>();	// list 변수 선언
list.add("홍길동");	// 맨 끝에 객체 추가
list.add(1, "전우치");	// 지정된 인덱스에 객체 삽입
String str = list.get(1);	// 인덱스로 객체 검색
list.remove(0);	// 인덱스로 객체 삭제
list.remove("전우치");	// 객체 삭제
  • List 컬렉션에 객체를 추가할 때는 add() 메소드를, 찾아올 때는 get() 메소드를, 삭제할 때는  remove() 메소드를 사용한다.
  • 'list 변수 선언'에서 <String>은 List 컬렉션에 저장되는 객체를 String 타입으로 하겠다는 것이다.
  • new ArrayList 는 기본 생성자로 ArrayList 를 사용하겠다는 것이고 ArrayList 객체를 생성하면 내부에 10개의 객체를 저장할 수 있는 초기 용량을 가지게 된다. 또한 객체 수가 늘어나면 용량이 자동 증가한다.

 

 

ArrayList

 

  • ArrayList에 객체를 추가하면 0번 인덱스부터 차례대로 저장된다.
  • 특정 인덱스의 객체를 제거하면 바로 뒤 인덱스부터 마지막 인덱스까지 모두 앞으로 1씩 당겨진다. 
  • 또한 특정 인덱스에 객체를 삽입하면 해당 인덱스부터 마지막 인덱스까지 모두 1씩 밀려난다.
  • 그렇기때문에 저장된 객체 수가 많고, 특정 인덱스에 객체를 추가하거나 삭제하는 일이 많다면 ArrayList 사용하는 것은 바람직하지 않다.
  • 하지만 인덱스를 이용해서 객체를 찾거나 맨 마지막에 객체를 추가하는 경우에는 ArrayList를 사용하는 것이 좋다.

 

 

Vector

 

  • Vector은 ArrayList와 달리 동기화된 메소드로 구성되어 있어 멀리 스레드가 동시에 Vector의 메소드를 실행할 수 없고, 하나의 스레드가 메소드를 실행을 완료해야만 다른 스레드가 메소드를 실행 할 수 있다. 
  • 그래서 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제 할 수 있다. 
  • 특정 인덱스의 객체를 제거하면 바로 뒤 인덱스부터 마지막 인덱스까지 모두 앞으로 1씩 당겨진다. 삽입할 경우도 마찬가지인다.

 

 

LinkedList

 

  • ArrayList와 사용 방법은 똑같으나 내부 구조는 완전 다르다.
  • ArrayList는 내부 배열에 객체를 저장해서 관리하지만, LinkedList는 인접 참조를 링크해서 체인처럼 관리한다.
  • LinkedList에서 객체를 제거하면 앞뒤 링크만 변경되고 나머지 링크는 변경되지 않는다. 삽입할 경우도 마찬가지인다.
  • 빈번한 객체 삭제와 삽입이 일어나는 곳에서 사용하기 좋다.

 

구분 순차적으로 추가/삭제 중간에 추가/삭제 검색
ArrayList 빠르다 느리다 빠르다
LinkedList 느리다 빠르다 느리다

 

 

 

Set 컬랙션

 

  • list  컬렉션은 객체의 저장 순서를 유지하지만, Set 컬렉션은 저장 순서가 유지되지 않는다.
  • 객체를 중복 저장할 수 없고, 하나의 null만 저장할 수 있다.
  • Set 컬렉션에는 HashSet, LinkedHashSet, TreeSet 등이 있다. 인덱스로 관리하지 않기 때문에 인덱스를 매개값으로 갖는 메소드가 없다.
  • 또한 인덱스로 객체를 검색해서 가져오는 메소드가 없다.
  • 대신 전체 객체를 대상으로 한 번씩 반복해서 가져오는 반복자를 제공한다. 반복자는 Iterator 인터페이스를 구현한 객체를 말하며 iterator() 메소드 호출 시 얻을 수 있다.
Set<String> set = new HashSet<String>();
Iterator<String> iterator = set.iterator();
  • Iterator에서 하나의 객체를 가져올 때는 next()메소드를 사용한다. 메소드 사용전 가져올 객체가 있는지 확인하는 것이 좋다.
  • hasNext() 메소드는 가져올 객체가 있으면 true를 리턴, 없으면 false를 리턴한다.
while(iterator.hasNext()){
	
    // String 객체 하나를 가져옴
	String str = iterator.next();
}
  • Set 컬렉션에서 Iterator의 next() 메소드로 가져온 객체를 제거하고 싶다면 remove() 메소드를 호출하면된다. Iterator의 메소드이지만 실제 Set 컬렌션에서 객체가 제거된다.
while(iterator.hasNext()){
	
    String str = iterator.next();
    if(str.equals("홍길동")){
    	
       	iterator.remove();
    }
}
  • List 컬렉션과 마찬가지로 객체를 추가할 때는 add() 메소드를, 삭제할 때는  remove() 메소드를 사용한다.

 

HashSet

 

Set<String> set = new Hashset<String>();
Set<String> set = new Hashset<>();
  • HashSet의 <> 생략 시 왼쪽 Set에 지정된 타입을 따라간다.
  • HashSet은 객체들을 순서 없이 저장하고 동일한 객체는 중복 저장하지 않는다.
  • HashSet이 판단하는 동일한 객체란 꼭 같은 인스턴스를 뜻하지는 않는다.
  • HashSet은 객체를 저장하기 전에 먼저 객체의 hashCode() 메소드를 호출해서 해시코드를 얻어내고 이미 저장되어 있는 객체들의 해시코드와 비교한 후 동일 해시코드가 있다면 다시 equals() 메소드로 두 객체를 비교해서 true가 나오면 동일한 객체로 판단하여 중복 저장하지 않는다.

 

 

Map 컬렉션

 

  • Map 컬렉션은 키와 값으로 구성된 Map.Entry 객체를 저장하는 구조를 가지고 있다.
  • Entry는 Map 인터페이스 내부에 선언된 중첩 인터페이스, 여기서 키와 값은 모두 객체이다.
  • 키는 중복 저장될 수 없지만 값은 중복 저장될 수 있다.
  • 기존에 저장된 키와 동일한 키로 값을 저장하면 기존의 값은 없어지고 새로운 값으로 대체된다.
  • Map 컬렉션에는 HashMap, Hashtable, LinkedHashMap, Properties, TreeMap 등이 있다.
  • 키로 객체들을 관리하기 때문에 키를 매개값으로 같는 메소드가 많다.
  • List 컬렉션과 마찬가지로 객체를 추가할 때는 add() 메소드를, 찾아올 때는 get() 메소드를, 삭제할 때는  remove() 메소드를 사용한다.
Map<String, Integer> map = new HashMap<String, Integet>();
map.put("홍길동". 10);	// 객체 추가
int score = map.get("홍길동");	// 객체 찾기
map.remove("홍길동");	// 객체 삭제
  • Map<String, Integer>로 map 변수를 선언했다. 이것은 Map 컬렉션에 저장되는 키 객체는 String 타입으로 값 객체는 Integer 타입으로 하겠다는 것이다.
  • 객체 추가에서는 첫번째 매개값은 문자열이고 두번째 매개값은 10이 포장된 Integer 객체(자동 박싱)가 된다.

 

  • 저장된 전체 객체를 대상으로 하나씩 얻고 싶을 경우 두가지 방법이 있다. 첫번째는 keySet() 메소드로 모든 키를 Set 컬렉션으로 얻은 다음, 반복자를 통해 키를 하나씩 얻고 get() 메소드를 통해 값을 얻는 방법이다.
Map<String, Integer> map = new HashMap<String, Integet>();
Set<K> ketSet = map.keySet();
Interator<K> keyIterator = ketSet,iterator();

while(keyIterator.hashNext()){
	
    K key = keyIterator.next();
    V value = map.get(key);
}

 

  • 두 번째는 entrySet() 메소드로 모든 Map.Entry를 Set 컬렉션으로 얻은 다음 반복자를 통해 Map.Entry를 하나씩 얻고 getKey()와 getValue() 메소드를 이용해 키와 값은 얻는 방법이다.
Set<Map.Entry<K, V>> entrySet = map.entrySet();
Interator<Map.Entry<K, V>> entryIterator = entrySet.iterator();

while(entryIterator.hashNext()){
	
    Map.Entry<K, V> entry = entryIterator.next();
    K key = entry.getKey();
    V value = entry.getValue();
}

 

 

 

HashMap

 

 

  • HashMap의 키로 사용할 객체는 hashCode()와 equals() 메소드를 재정의해서 동등 객체가 될 조건을 정해야 한다.
  • 객체가 달라도 동등 객체라면 같은 키로 간주하고 중복 저장되지 않도록 하기 위함이다.
  • 동등 객체의 조건은 hashCode()의 리턴값이 같아야 하고, equals() 메소드가 true를 리턴해야한다. 
  • 주로 키 타입은 String 타입을 많이 사용하는데 String은 문자열이 같은 경우 동등 객체가 될 수 있도록 hashCode()와 equals() 메소드가 재정의되어 있다.
  • HashMap을 생성하기 위해서는 키 타입과 값 타입을 타입 파라미터로 주고 기본 생성자를 호출하면 된다.
  • 키와 값의 타입은 기본 타입(byte, short, int, float, double, boolean, char)을 사용할 수 없고 클래스 및 인터페이스 타입만 사용가능하다. 

 

 

Hashtable

 

  • Hashtable은 HashMap과 동일한 내부 구조를 가진다.
  • Hashtable도 키로 사용할 객체는 hashCode()와 Equals() 메소드를 재정의해서 동등 객체가 될 조건을 정해야 한다.
  • HashMap과의 차이는 Hashtable은 동기화된 메소드로 구성되어 있기 때문에 멀티 스레드가 동시에 Hashtable의 메소드들은 실행할 수 없고 하나의 스레드가 실행을 완료해야만 다른 스레드를 실행할 수 있다는 것이다.