GeehDev

[Java] 컬렉션 - 1) 컬렉션과 List(ArrayList, LinkedList, Vector) 본문

Study/Java

[Java] 컬렉션 - 1) 컬렉션과 List(ArrayList, LinkedList, Vector)

geehyun 2024. 9. 15. 16:32

컬렉션의 경우 내용이 많아

  1. [Java] 컬렉션 - 1) 컬렉션과 List(ArrayList, LinkedList, Vector)
  2. [Java] 컬렉션 - 2) Set (HashSet, LinkedHashSet, TreeSet)
  3. [Java] 컬렉션 - 3) Set(HashMap, HashTable, LinkedHashMap, TreeMap) - 작성중

의 3개의 시리즈로 구성됩니다.

 

[Java] 컬렉션 - 1) 컬렉션과 List

컬렉션컬렉션이란 동일한 타입을 묶어서 관리하는 자료구조를 말합니다.이렇게만 설명할 경우 굉장히 배열(Array)와 비슷해 보이는데,어느정도 비슷한 면은 있지만 가장 큰 차이점은 배열은 생

geehyun.tistory.com

 

 

[Java] 컬렉션 - 2) Set (HashSet, LinkedHashSet, TreeSet)

컬렉션의 경우 내용이 많아 [Java] 컬렉션 - 1) 컬렉션과 List(ArrayList, LinkedList, Vector)[Java] 컬렉션 - 2) Set (HashSet, LinkedHashSet, TreeSet)[Java] 컬렉션 - 3) Set(HashMap, HashTable, LinkedHashMap, TreeMap)의 3개의 시리

geehyun.tistory.com

 


 

컬렉션

컬렉션이란 동일한 타입을 묶어서 관리하는 자료구조를 말합니다.
이렇게만 설명할 경우 굉장히 배열(Array)와 비슷해 보이는데,

어느정도 비슷한 면은 있지만 가장 큰 차이점은 배열은 생성한 시점에 저장공간을 확정해야한다면, 컬렉션은 저장공간을 동적으로 관리할 수 있다는 점 입니다.

컬렉션구조

컬렉션의 경우 특성에 따라 구분한 List<E>, Set<E>, Map<K, V>과 기존 컬렉션 기능을 확장 또는 조합한 Stack<E>, Queue<E>가 있습니다.

 

  • List<E>
    Collection<E>를 상속받은 컬렉션 인터페이스로 원소를 인덱스로 관리한다는 점에서 배열과 가장 유사한 구조를 갖고 있습니다.
    해당 인터페이스를 구현한 구현 클래스로는 ArrayList<E>, Vector<E>, LinkedList<E>가 있습니다.
  • Set<E>
    Collection<E>를 상속받은 컬렉션 인터페이스로 원소 집합체라는 개념의 컬렉션으로, 인덱스의 개념이 없어 원소(데이터) 간의 중복을 허용하지 않는게 특징입니다.
    해당 인터페이스를 구현한 구현 클래스로는 HashSet<E>, LinkedHashSet<E>, TreeSet<E>이 있습니다.
  • Map<K, V>
    Key : value의 엔트리로 구성*
    되는 Map<K, V>은 구조상의 이유로 Collection<E>과 별도로 존재하는 인터페이스 입니다만, 컬렉션으로 분류됩니다.
    해당 인터페이스를 구현한 구현 클래스로는 HashMap<K, V>, LinkedHashMap<K, V>, HashTable<K, V>, TreeMap<K, V>이 있습니다.
💡 TreeSet<E>TreeMap<K, V>
    • TreeSet<E>
      Set<E>을 상속받아 정렬기능을 추가한 SortedSet<E>인터페이스와 검색기능을 추가한 NavigableSet<E>인터페이스를 구현한 구현클래스 입니다.
    • TreeMap<K, V>
      Map<K, V>을 상속받아 정렬기능을 추가한 SortedMap<K, V>인터페이스를 상속받아 검색기능을 추가한 NavigableMap<K, V>인터페이스를 구현한 구현클래스 입니다.

      따라서 두 클래스 모두 추가된 정렬, 검색 기능을 사용하기 위해서는 객체를 생성할 때 Set<E>, Map<K, V>가 아닌 TreeSet<E>, TreeMap<K, V>을 자료형으로 객체를 생성해야합니다.

 

  • Stack<E>
    Vector<E>의 자식 클래스*
    로, LIFO(Last In First Out) 후입선출 자료구조를 구현한 클래스 입니다.
    다른 컬렉션들이 인터페이스로 작성되어 이를 구현한 구현클래스로 객체 생성을 해야하는 것과 다르게 자체적으로 객체 생성이 가능한 클래스 입니다!
  • Queue<E>
    Collection<E>를 상속받은 컬렉션 인터페이스로, FIFO(First In First Out) 선입선출 자료구조를 구현한 인터페이스 입니다.
    해당 인터페이스를 구현한 구현 클래스는 LinkedList<E> 입니다.

💡 Collection 각 특성 요약

Collection 각 특성 요약

List

배열과 가장 비슷한 구조를 가지고있는 자료구조 입니다.
배열과의 차이점은, 저장공간을 동적으로 관리할 수 있다는 점에서 차이점이 있습니다.
인덱스(순서)가 있는 데이터 리스트로, 순서로 구분하기 때문에 데이터간 중복을 허락합니다.

ArrayList

  • 데이터를 인덱스로 관리합니다.
  • 저장공간을 동적으로 관리할 수 있습니다.
  • 객체 생성시 생성자(저장용량)로 지정해줄 수 있으며, 미지정 시 10으로 설정됩니다.
    //사용법
    ArrayList<제네릭 타입지정> 참조변수 = new ArryaList<제네릭 타입지정>();
    ArrayList<제네릭 타입지정> 참조변수 = new ArryaList<제네릭 타입지정>(사이즈);
    // 다형성에 따라 부모인터페이스인 List 타입으로 객체 생성가능
    List<제네릭 타입지정> 참조변수 = new ArryaList<제네릭 타입지정>();
    List<제네릭 타입지정> 참조변수 = new ArryaList<제네릭 타입지정>(사이즈);
    // 사용예시
    List<String> aList = new ArrayList<String>();
    aList.add("바보");    // add()로 리스트에 값 추가
    aList.add("멍청이");
    aList.add("말미잘"); 
    System.out.println(aList); // 출력 : [바보, 멍청이, 말미잘]

Vector

  • 데이터를 인덱스로 관리합니다.
  • 저장공간을 동적으로 관리할 수 있습니다.
  • 객체 생성시 생성자(저장용량)으로 지정해줄 수 있으며, 미지정 시 10으로 설정됩니다.
  • 동기화 메서드(Synchronized method)로 구현되어있어 멀티쓰레드에 적합합니다.
    (싱글쓰레드에서는 ArrayList를 사용하는 것 이 효율적입니다.)
    //사용법
    Vector<제네릭 타입지정> 참조변수 = new Vector<제네릭 타입지정>();
    Vector<제네릭 타입지정> 참조변수 = new Vector<제네릭 타입지정>(사이즈);
    // 다형성에 따라 부모인터페이스인 List 타입으로 객체 생성가능
    List<제네릭 타입지정> 참조변수 = new Vector<제네릭 타입지정>();
    List<제네릭 타입지정> 참조변수 = new Vector<제네릭 타입지정>(사이즈);
    // 사용예시
    List<String> vList = new Vector<String>();
    vList.add("바보");    // add()로 리스트에 값 추가
    vList.add("멍청이");
    vList.add("말미잘"); 
    System.out.println(vList); // 출력 : [바보, 멍청이, 말미잘]

LinkedList

  • 데이터간 앞뒤 원소의 정보를 저장하는 방식의 구조 입니다.
  • 인덱스를 사용할 수는 있지만 인덱스 정보를 저장하고있지않아 사용할 때마다 계산해야해서 검색 속도가 느립니다.
  • 데이터를 중간에 추가/삭제 시 추가한 데이터의 앞뒤 연결정보만 수정하면되서 속도가 빠릅니다.
  • 저장공간을 동적으로 관리할 수 있습니다.
  • 객체 생성시 생성자(저장용량)으로 지정할 수 없습니다.
    //사용법
    LinkedList<제네릭 타입지정> 참조변수 = new LinkedList<제네릭 타입지정>();
    // 다형성에 따라 부모인터페이스인 List 타입으로 객체 생성가능
    List<제네릭 타입지정> 참조변수 = new LinkedList<제네릭 타입지정>();
    // 사용예시
    List<String> lList = new LinkedList<String>();
    lList.add("바보");    // add()로 리스트에 값 추가
    lList.add("멍청이");
    lList.add("말미잘"); 
    System.out.println(lList); // 출력 : [바보, 멍청이, 말미잘]

💡 ArrayList vs LinkedList


구분 ArrayList LinkedList
저장방식 데이터에 인덱스를 저장하여 관리| 각 원소간 앞뒤 원소의 정보를 저장하여 관리
추가(add), 삭제(remove) 느림 🐢 빠름 🐇
검색(get) 빠름 🐇 느림 🐢
  • 추가/삭제
    • ArrayList의 경우 원소가 중간에 추가/삭제 될 경우 해당 원소를 추가/삭제 후 그 뒤에 모든 원소들의 인덱스를 수정해주는 작업이 필요하여 비교적 속도가 느립니다.
    • LinkedList의 경우 원소가 중간에 추가/삭제 될 경우 해당 원소의 앞뒤 원소에서대한 정보만 변경해주면되기 떄문에 비교적 속도가 빠릅니다.
  • 검색
    • ArrayList의 경우 각 원소마다 인덱스 정보를 저장하고 있기 때문에 원소 검색에 비교적 속도가 빠릅니다.
    • LinkedList의 경우 각 원소마다 앞뒤 원소의 정보만 저장하고 인덱스 정보가 없기 때문에 특정 인덱스의 정보를 찾기위해서는 앞에서부터 쭉 찾아야하기 때문에 비교적 속도가 느립니다.

주요 메서드

  • 데이터 추가
    NO 리턴타입 메서드명 설명
    1 boolean add(E element) - 매개변수로 입력된 원소를 리스트의 마지막에 추가합니다.
    - 해당 리스트 객체를 생성할 때 제네릭 타입으로 지정한 타입만 추가할 수 있습니다.
    2 void add(int index, E element) - 매개변수로 입력된 원소를 입력한 인덱스에 추가합니다.
    - 해당 리스트 객체를 생성할 때 제네릭 타입으로 지정한 타입만 추가할 수 있습니다.
    3 boolean addAll(Collection<? extends E> c) - 매개변수로 입력된 컬렉션 전체를 리스트 마지막에 추가합니다.
    - 해당 메서드를 이용하여 해당 객체에 대하여 깊은 복사를 할 수 있습니다.
    4 boolean addAll(int index, Collection<? extends E> c) - 매개변수로 입력된 컬렉션 전체를 입력한 인덱스에 추가합니다.
    - 해당 메서드를 이용하여 해당 객체에 대하여 깊은 복사를 할 수 있습니다.
  • 데이터 변경
    NO 리턴타입 메서드명 설명
    5 E set(int index, E element) - 인덱스 위치의 원소값을 입력한 원소값으로 변경합니다.
  • 데이터 삭제
    NO 리턴타입 메서드명 설명
    6 E remove(int index) - 인덱스 위치의 원소를 삭제합니다.
    7 boolean remove(Object o) - 원소 중 매개변수 입력과 동일한 객체를 삭제합니다.
    - 매개변수 타입이 Object임으로 매개변수 입력 시 해당하는 원소의 타입과 동일한 객체로 입력해줘야합니다.
    8 void clear() - 해당 리스트의 전체 원소를 삭제합니다.
  • 데이터 정보추출
    NO 리턴타입 메서드명 설명
    9 E get(int index) - 인덱스 위치의 원소 값을 반환해줍니다.(리스트 사이즈 변동 X)
    10 int size() - 리스트 내 원소 개수를 반환해줍니다.
    11 boolean isEmpty() - 리스트 내 원소가 한개도 없으면 true, 1개 이상 있으면 false를 반환합니다.
    - empty와 null은 완전히 다른 개념으로 empty는 리스트가 비어있을 뿐 리스트는 존재한 경우 입니다.
  • 배열(Array)로 변환
    NO 리턴타입 메서드명 설명
    12 Object[] toArray() - 리스트를 Object 타입의 배열로 변환합니다.
    - Object[]이기 때문에 변환된 배열을 실제 사용시에는 해당하는 타입으로 다운캐스팅이 필요할 수 있습니다.
    13 T[] toArray(T[] t) - 리스트를 입력매개변수로 받은 타입의 배열로 변환합니다.
    - 입력매개변수의 배열 객체에서 배열의 크기를 입력해줘야합니다.(배열의 특징)
    - 리스트의 사이즈보다 작은 크기를 입력 시 자동으로 리스트 사이즈만큼으로 확장하여 배열로 변환합니다.
    - 리스트의 사이즈보다 큰 크기를 입력 시 남은 자리에 null이 들어간 배열로 변환합니다.

💡 리스트를 배열로 변환하는건 있는데... 배열을 리스트로 변환하는건?
toArray로 리스트를 배열로 변환하는 방법을 확인했습니다. 그러면 그 반대로 배열을 리스트로 변환하는 것도 있을까요?
Arrays.asList()메서드를 통해 리스트로 변환할 수 있습니다.
다만, 해당 메서드를 이용하여 만든 List의 경우 배열(Array)에 List라는 껍데기만 씌운, 래핑(wrapping)해놓은 개념으로 내부 구조는 배열과 동일합니다. 즉 사이즈를 늘리거나 줄일 수 없습니다.
사이즈 변경이 없는 다른 List의 메서드는 모두 이용이 가능합니다.

// 사용법
  List<제네릭 타입> 참조변수 = Arrays.asList(저장할 제네릭 타입의 데이터);
  List<제네릭 타입> 참조변수 = Arrays.asList(제네릭 타입의 배열 그자체);
  >
  // 사용예시
  List<Integer> arrToList1 = Array.asList(1, 2, 3, 4);
  String[] arr = {"가", "나", "다"};
  List<String> arrToList2 = Array.asList(arr);
  System.out.println(arrToList1);   // 출력 : [1, 2, 3, 4]
  System.out.println(arrToList2);   // 출력 : [가, 나, 다]
  arrToList1.add(5);                // 오류 발생 : UnsupportedOperationException
  arrToList2.add("라");             // 오류 발생 : UnsupportedOperationException
  arrToList1.remove(1);             // 오류 발생 : UnsupportedOperationException
  arrToList2.remove(1);             // 오류 발생 : UnsupportedOperationException
  arrToList1.clear();               // 오류 발생 : UnsupportedOperationException
  arrToList2.clear();               // 오류 발생 : UnsupportedOperationException
  arrToList1.set(0,10);             // 정상동작
  arrToList2.set(0,"화");           // 정상동작
  System.out.println(arrToList1);   // 출력 : [10, 2, 3, 4]
  System.out.println(arrToList2);   // 출력 : [화, 나, 다]
  System.out.println(arrToList1.get(2));   // 출력 : 3
  System.out.println(arrToList2.get(2));   // 출력 : 다

 

 

  • 사용 예시
  // 1. add(E element)
  List<Integer> aList = new ArrayList<Integer>();
  aList.add(1);
  aList.add(2);
  aList.add(3);
  System.out.println(aList);   // 출력 : [1, 2, 3]
  
  // 2. add(int index, E element)
  aList.add(0,10);
  aList.add(1,9);
  System.out.println(aList);   // 출력 : [10, 9, 1, 2, 3]
  
  // 3. addAll(Collection<? extends E> c)
  List<Integer> aList1 = new ArrayList<Integer>();
  List<Integer> aList2 = new ArrayList<Integer>();
  aList1.add(1);
  aList1.add(2);
  aList2.add(10);
  aList2.add(aList1);
  System.out.println(aList2);   // 출력 : [10, 1, 2]
  
  // 4. addAll(int index, Collection<? extends E> c)
  List<Integer> aList3 = new ArrayList<Integer>();
  List<Integer> aList4 = new ArrayList<Integer>();
  aList3.add(1);
  aList3.add(2);
  aList4.add(10);
  aList4.add(9);
  aList4.addAll(1, aList3);
  System.out.println(aList4);   // 출력 : [10, 1, 2, 9]
  
  // 5. set(int index, E element)
  List<Integer> aList5 = new ArrayList<Integer>();
  aList5.add(1);
  aList5.add(2);
  aList5.add(3);
  System.out.println(aList5);   // 출력 : [1, 2, 3]
  aList.set(1, 10);
  System.out.println(aList5);   // 출력 : [1, 10, 3]
  
  // 6. remove(int index)
  List<Integer> aList6 = new ArrayList<Integer>();
  aList6.add(1);
  aList6.add(2);
  aList6.add(3);
  System.out.println(aList6);   // 출력 : [1, 2, 3]
  aList6.remove(1);
  System.out.println(aList6);   // 출력 : [1, 3]
  
  // 7. remove(Object o)
  List<Integer> aList7 = new ArrayList<Integer>();
  aList7.add(1);
  aList7.add(2);
  aList7.add(3);
  System.out.println(aList7);   // 출력 : [1, 2, 3]
  aList7.remove(new Integer(1));
  // 이 때 그냥 1을 입력하면 원소 1이 아니라, 인덱스 1로 인식해버립니다.
  // 객체로 매개변수를 입력해줘야한다는 점 명심! 
  System.out.println(aList7);   // 출력 : [2, 3]
  
  //8. clear()
  List<Integer> aList8 = new ArrayList<Integer>();
  aList8.add(1);
  aList8.add(2);
  aList8.add(3);
  System.out.println(aList8);   // 출력 : [1, 2, 3]
  aList8.clear();
  System.out.println(aList8);   // 출력 : []
  
  // 9. get(int index)
  List<String> aList9 = new ArrayList<String>();
  aList9.add("가");
  aList9.add("나");
  aList9.add("다");
  System.out.println(aList9);   // 출력 : [가, 나, 다]
  System.out.println(aList9.get(0));   // 출력 : 가
  System.out.println(aList9.get(1));   // 출력 : 나
  System.out.println(aList9.get(2));   // 출력 : 다
  
  // 10. size()
  List<String> aList10 = new ArrayList<String>();
  aList10.add("가");
  aList10.add("나");
  aList10.add("다");
  System.out.println(aList10);   // 출력 : [가, 나, 다]
  System.out.println(aList10.size());   // 출력 : 3
  aList10.remove(1);
  System.out.println(aList10);   // 출력 : [가, 다]
  System.out.println(aList10.size());   // 출력 : 2
  aList10.clear();
  System.out.println(aList10);   // 출력 : []
  System.out.println(aList10.size());   // 출력 : 0
  
  // 11. isEmpty()
  List<String> aList11 = new ArrayList<String>();
  aList11.add("가");
  aList11.add("나");
  aList11.add("다");
  System.out.println(aList11);   // 출력 : [가, 나, 다]
  System.out.println(aList11.isEmpty());   // 출력 : false
  aList11.clear();
  System.out.println(aList11);   // 출력 : []
  System.out.println(aList11.isEmpty());   // 출력 : true
  
  // 12. toArray()
  List<String> aList11 = new ArrayList<String>();
  aList11.add("가");
  aList11.add("나");
  aList11.add("다");
  Object[] objArr = aList11.toArray();
  System.out.println(Arrays.toString(objArr));   // 출력 : [가, 나, 다]
  // toArray()메서드를 이용해 변환한 배열의 타입은 Object[]라는 점을 꼭 명심해야합니다.
  
  // 13. toArray(T[] t)
  List<String> aList12 = new ArrayList<String>();
  aList12.add("가");
  aList12.add("나");
  aList12.add("다");
  String[] strArr1 = aList12.toArray(new String[0]); 
  // 대상 리스트 사이즈보다 작게 입력 시 자동으로 리스트의 사이즈크기의 배열로 변환
  String[] strArr2 = aList12.toArray(new String[5]);
  // 대상 리스트 사이즈보다 크게 입력 시 남는 자리에는 null이 입력된 배열로 변환
  System.out.println(Arrays.toString(strArr1));   // 출력 : [가, 나, 다]
  System.out.println(Arrays.toString(strArr2));   // 출력 : [가, 나, 다, null, null]

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

[Java] 컬렉션 - 2) Set (HashSet, LinkedHashSet, TreeSet)  (0) 2024.09.15
[Java] JavaBeans  (0) 2024.09.15
[Java] 제네릭  (2) 2024.09.15
[Java] 예외 처리  (1) 2024.09.15
[Java] 이너 클래스  (0) 2024.09.15