⭐️ 컬렉션 프레임워크란 ?
컬렉션 프레임워크란 컬렉션과 프레임워크가 합쳐진 말이다.
컬렉션이란 자료구조 개념이 내장되어 있는 클래스로 자바에서 제공하는
"자료구조"를 담당하는 "프레임워크"다.
자료구조 : 방대한 데이터를 보다 효울적으로 관리(C, R, U, D 등)할 수 있도록 해주는 구조이다.
프레임워크 : 이미 만들어져있는 툴 (코드 더미)이다.
즉, 자바는 방대한 데이터를 보다 효울적으로 관리 할 수 있는 코드 더미를 제공하는데 이것의
알고리즘을 구조화 하여 클래스, 인터페이스로 구현해 놓은것이 컬렉션 프레임워크이다.
컬렉션 프레임워크의 의미가 아닌 사용 형태로 클래스, 인터페이스로 정리해보면
인터페이스 : List, Set, Map 등이 있다.
인터페이스를 구현하는 클래스 : ArrayList, HashSet, HashMap 등이 있다.
정리하자면 ‼️
자료를 다루는 규칙(인터페이스)을 먼저 정의하고,
그 규칙을 실제로 동작하게 만드는 구현 클래스(구현체)를 제공하여
개발자가 다양한 자료구조를 일관된 방법으로 쉽게 사용할 수 있도록 만든 체계이다.
⭐️ 컬렉션 프레임 워크의 장점
✨ 인터페이스와 다형성을 이용한 객체지향적 설계를 통해 표준화되어 있기 때문에,
사용법을 익히기에도 편리하고 재사용성이 높다.
✨ 데이터 구조 및 알고리즘의 고성능 구현을 제공하여 프로그램의 성능과 품질을 향상시킨다.
✨ 이미 구현되어있는 API를 사용하면 되기에, 새로운 API를 익히고 설계하는 시간이 줄어든다
✨ 소프트웨어 재사용을 촉진한다. 만일 자바에서 지원하지 않는 새로운 자료구조가 필요하다면,
컬렉션들을 재활용하여 조합하여 새로운 알고리즘을 만들어낼 수 있다.
⭐️ 주요 인터페이스
주요 인터페이스에는 3개의 큰 인터페이스를 중심으로 구성되어 있다.
🔥 List
List는 "순서가 있는 데이터 집합"을 다루기 위한 인터페이스이다.
요소들이 순차적으로 저장되고, 중복된 데이터 허용이 가능하다.
또한 인덱스 기반으로 요소에 접근할 수 있다.
대표적인 구현체로는 ArrayList, LinkedList가 있다.
ArrayList : 내부적으로 배열을 사용하고 , 읽기 속도가 빠르다.
LinkedList : 노드를 연결하는 방식이며 삽입/삭제가 빠르다.
[ ArrayList 사용 예제 ]
List list = new ArrayList(); // 크기를 지정해도되고 안해도 됨
System.out.println(list); // 빈 배열상태
// 1.add(E e) : 리스트공간 끝에 전달된 데이터를 추가시켜주는 메서드
list.add(new Music("에피소드" , "이무진"));
list.add(new Music("천상연" , "이창섭"));
list.add(new Music("비의 랩소디" , "임재현"));
list.add("끝");
// 지정된 크기보다 더 많이 넣어도 에러가 발생하지 않는다. -> 징점 1. 크기제약 X
// 다양한 타입의 데이터를 담을 수 있음 -> 장점 2. 여러타입을 보관할 수 있다. (Object로 만들어졌기때문)
System.out.println(list); // list의 특징 : 순서를 유지하면서 담긴다. (0번 인덱스부터 차근차근)
🔥 Set
Set은 "순서를 보장하지 않고, 중복을 허용하지 않는 집합"을 다루기 위한 인터페이스이다.
중복된 데이터를 저장할 수 없고, 저장 순서를 보장하지 않거나, 특정 정렬 기준을 적용할 수도 있다.
대표적인 구현체로는 HashSet, TreeSet이 있다.
HashSet : 순서가 없고, 빠른저장 / 검색에 용이하다.
TreeSet : 정렬된 상태로 저장이 된다. 기본적으로 오름차순이다.
[ Hash Set 사용 예제 ]
HashSet<String> hs1 = new HashSet();
hs1.add("반갑습니다.");
hs1.add(new String("반갑습니다."));
hs1.add(new String("여러분."));
hs1.add(new String("안녕하세요."));
hs1.add(new String("여러분."));
System.out.println(hs1); // 저장순서를 유지하지 않는다. 중복된 데이터(동일 객체) 보관 불가
위와같이 저장순서도 보장되지 않고, 중복데이터 또한 저장이 되지 않는것을 볼 수 있다.
자 그러면 여기서 이런 생각이 들 수 있을 것이다.
🧐 중복이 뭔지를 판단하려면 두 객체가 같다는걸 비교해야하는데 어떻게 하는것인가?
이때 사용하는게 hashCode()와 equals() 메서드이다.
🔥 동작 흐름
1. 먼저 hashCode()를 비교한다.
* hasCode : 해당 객체의 주소값을 가지고 10진수 형태의 해시코드로 반환
만약 해시코드가 다르면 "다른 객체"로 간주하고 바로 끝낸다.
2. 해시코드가 같으면, equals()메서드를 호출하여 "내용비교"를 한다.
equals()가 true이면 중복이라고 판단해서 add()가 무시된다.
flase면 서로 다른 객체로 인식하고 저장한다.
String처럼 기본적으로 오버라이딩이 되어 있는 클래스는 문제없지만,
Student 같은 사용자 정의 클래스는 직접 equals()와 hashCode()를 오버라이딩 해줘야 한다.
오버라이딩을 하지 않으면 Object 기본 메서드의 equals()와 hashCode()를 사용하는데,
이건 "객체의 주소값"으로 비교하기 때문에 내용이 같아서 무조건 다른 객체로 간주하게 된다.
🔥 Map
Map은 Key-Value 상으로 데이터를 저장하는 구조의 인터페이스 이다.
Key를 기준으로 데이터를 저장하고, 검색한다.
Key는 중복 불가지만 Value는 중복 가능이다.
대표적인 구현체로는 HasMap, TreeMap이 있다.
HashMap : 빠른 저장/검색에 용이하고 순서가 없다.
TreeMap : Key를 기준으로 정렬하여 저장한다.
[ HashMap 사용 예제 ]
HashMap<String, Snack> hm = new HashMap();
HashMap<Snack, String> hm2 = new HashMap();
// 계층구조를 보면
// List계열 , Set계열의 클래스들은 Collection을 구현할 클래스이다.
// -> 객체를 추가하고자할 때 공통적으로 add메서드를 이용
// Map계열은 Collection을 구현한 클래스가 아니다.
// -> 객체를 추가할 때 put메서드를 사용(key, value 쌍으로 담는다.)
// 1. put(k,v) : map에 k , v 쌍으로 값을 추가하는 메서드.
hm.put("다이제", new Snack("초코맛", 2000));
hm.put("도리토스", new Snack("나초치즈맛", 500));
hm.put("먹태깡", new Snack("와사비맛", 600));
hm.put("틴틴", new Snack("초코맛", 2000));
hm2.put(new Snack("초코맛", 2000),"다이제");
hm2.put(new Snack("나초치즈맛", 500),"도리토스");
hm2.put(new Snack("와사비맛", 600), "먹태깡" );
hm2.put(new Snack("초코맛", 2000),"틴틴");
// -> 칼로리값 변경해도 맛만으로 동일객체로 판단하게 만들기
// 저장되는 순서 유지가 안됨! value값이 중복되어도 키값이 중복되지 않으면 저장됨
System.out.println(hm);
System.out.println(hm2);
List와 Set은 Collection을 구현한 클래스이지만, Map 계열은 Collection을 구현한 클래스가 아니기 때문에,
객체를 추가할때 add가 아닌 put메서드를 사용해서 Key, value 쌍으로 담는다.
여기서 실행결과를 보면 hm은 value를 중복으로 만들었고, hm2는 key를 중복으로 만들었다.
하지만 이때, Map은 key의 중복을 허용하지않기에 key가 초코맛인 value가 다이제 또는 틴틴중에 하나만
출력이 된다.
근데 매번 실행을 할때 순서가 없다고 하였는데, 같은 결과만 나오는 현상이 있었다.
이는 HashMap은 데이터를 저장할 때 "Key의 hasCode()"를 이용해서 버킷(bucket)이라는
공간에 나누어서 저장을 하는데
이 버킷이 어떤식으로 배치되냐면 hasCode()값, 초기 capacity, 해시 함수 충돌처리 같은 것에 따라 결정이 된다.
여기서 hashCode()는 객체를 숫자로 변환하는 메서드이며, 이 숫자를 가지고 "어디 버킷에 저장할지"를 결정한다.
따라서 hasCode()값이 다르면 다른 곳에 저장하고, 같으면 충돌이 발생할 수 있다.
capacit는 HashMap은 미리 크기(칸 개수)를 정해놓고 시작하는데 이 크기를 capcity(용량)이라고 한다.
자바8 기준 기본 값은 16이다.
따라서 capacity는 처음 만들어지는 버킷 칸 수이며, hashCode를 나눈 나머지로 어떤 칸에 들어갈지 결정한다.
해시 함수 충돌처리는 서로 다른 두 객체가 우연히 같은 버킷으로 배정될 수 있는데 이것을 해시 충돌이라고 한다.
충돌 처리 방법은 같은 칸에 데이터가 몰리면, 내부적으로 LinkedList에서 나중에 Tree로 변환해서 관리를 해준다.
이를 통해서 버킷 배치에 방식에 대해서 잠깐 알아보았다.
🧐 그러면 왜 항상 같은 순서처럼 보이는 것일까 ?
이는 항상 같은 자바 버전, 같은 코드 , 같은 실행 환경이기 때문에
내부에서 hashCode를 계산하는 방식이 일관되고, 그렇기 때문에 결과가 우연히 매번 비슷하게 나오는 것일뿐
다른 JVM, 다른 버전, 다른 PC에서 실행하면 순서가 바뀔 수 있다.
'IT 지식 (기술면접 대비)' 카테고리의 다른 글
SQL문 실행 순서 (4) | 2025.04.29 |
---|---|
Java의 어노테이션이란? (0) | 2025.04.25 |
인터페이스를 사용하는 이유는 무엇일까? (2) | 2025.04.21 |
GC (Garbage Collection)란? (1) | 2025.04.19 |
자바의 메서드 오버로딩과 오버라이딩 (2) | 2025.04.17 |