⦁ Comparator와 Comparable
- 객체 정렬에 필요한 메소드(정렬기준 제공)를 정의한 인터페이스
Comparable 기본 정렬기준을 구현하는데 사용
Comparator 기본 정렬기준 외에 다른 기준으로 정렬하고자 할 때 사용
public interface Comparable {
int compareTo(Object o); // 주어진 객체(o)를 자신과 비교
}
public interface Comparator {
int compare (Object o1, Object o2); // o1, o2 두 객체를 비교
boolean equals (Object obj);; // equals를 오버라이딩 하라는 뜻
}
- compare()와 compareTo() 는 두 객체의 비교결과를 반환하도록 작성
(양수 : 왼쪽이 큼 / 0 : 같다 / 음수 : 오른쪽이 큼)
ex)
import java.util.Arrays;
import java.util.Comparator;
class Descending implements Comparator {
public int compare(Object o1, Object o2) {
if(o1 instanceof Comparable && o2 instanceof Comparable) {
Comparable c1 = (Comparable)o1;
Comparable c2 = (Comparable)o2;
return c1.compareTo(c2) * -1 ; // -1을 곱해서 기본 정렬방식의 역으로 변경한다.
// 또는 c2.compareTo(c1)와 같이 순서를 바꿔도 된다.
}
return -1; // 비교할 수 없는 대상이면 -1을 반환..(왜 굳이 -1을 반환하는지는 모르겠음)
}
}
public class Ex11_7 {
public static void main(String[] args) {
String[] strArr = {"cat", "Dog", "lion", "tiger"};
Arrays.sort(strArr); // String의 Comparable구현에 의한 정렬(String의 기본정렬기준, 사전순)
System.out.println("strArr = "+Arrays.toString(strArr));
Arrays.sort(strArr, String.CASE_INSENSITIVE_ORDER); // 대소문자 구분 안하는 정렬기준
System.out.println("strArr = "+Arrays.toString(strArr));
Arrays.sort(strArr, new Descending()); // 역순 정렬
System.out.println("strArr = "+Arrays.toString(strArr));
}
}
⦁ Integer와 Comparable
public final class Integer extends Number implements Comparable {
...
public int compareTo(Object o) {
return compareTo((Integer)o);
}
public int compareTo(Integer anotherInteger) {
int thisVal = this.value;
int anotherVal = anotherInteger.value;
// 비교하는 값이 크면 –1, 같으면 0, 작으면 1을 반환한다.
return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1 ));
}
...
}
-> Integer는 Comparable을 구현하고 있음. 따라서 compareTo 메소드를 가지고 있으며 기본 정렬기준을 갖고 있음
(정렬할 때는 정렬 대상과 정렬기준이 필요)
⦁ HashSet – 순서X, 중복X
▶ HashSet
- Set 인터페이스를 구현한 대표적인 컬렉션 클래스
- 순서를 유지하려면, LinkedHashSet클래스를 사용하면 된다.
▶ TreeSet
- 범위 검색과 정렬에 유리한 컬렉션 클래스
- HashSet보다 데이터 추가, 삭제에 시간이 더 걸림
⦁ HashSet의 주요 메소드
생성자)
HashSet()
HashSet(Collection c)
HashSet(int initialCapacity) // 초기 용량
HashSet(int initialCapacity, float loadFactor) // 초기용량과 용량을 언제 늘릴것인지
// loadFactor가 0.8 -> 80%
메소드)
boolean add(Object o)
boolean addAll(Collection c) // 합집합
boolean remove(Object o)
boolean removeAll(Collection c) // 차집합
boolean retainAll(Collection c) // 조건부 삭제 (교집합)
void clear() // 모두 삭제
boolean contains(Object o) // 이 객체가 포함되어 있는지
boolean containsAll(Collection c) // Collection c에 담긴 여러 객체가 모두 포함되어 있는지
Iterator iterator()
isEmpty() // 비었는지 확인
int size() // 저장된 객체의 개수
Object[] toArray() // 객체배열로 반환
Object[] toArray(Object[] a) // 객체배열로 반환
ex)
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Ex11_9 {
public static void main(String[] args) {
Object[] objArr = {"1",new Integer(1), "2","2","3","3","4","4","4"};
Set set = new HashSet();
for(int i=0; i<objArr.length; i++) {
set.add(objArr[i]); // HashSet에 objArr의 요소들을 저장한다.
}
// for(Object obj : objArr) {
// set.add(obj);
// }
// HashSet에 저장된 요소들을 출력한다.
System.out.println(set);
// HashSet에 저장된 요소들을 출력한다.(Iterator이용)
Iterator it = set.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
ex)
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class Ex11_10 {
public static void main(String[] args) {
Set set = new HashSet();
// set의 크기가 6보다 작은 동안 1~45사이의 난수를 저장
for(int i=0; set.size() < 6; i++) {
int num = (int)(Math.random()*45) + 1;
// set.add(new Integer(num));
set.add(num);
}
List list = new LinkedList(set); // LinkedList(Collection c)
Collections.sort(list); // Collections.sort(List list)
System.out.println(list);
}
}
* 정렬은 순서를 유지해야 함. Set은 순서가 없으므로 정렬 불가능.
Set을 List에 넣어서 저장 후 정렬을 해야 함.
- HashSet은 객체를 저장하기 전에 기존에 같은 객체가 있는지 확인함
같은 객체가 없으면 저장하고, 있으면 저장하지 않는다.
- boolean add(Object o)는 저장할 객체의 equals()와 hashCode()를 호출
equals()와 hashCode()가 오버라이딩 되어 있어야 함
-> equals()는 iv를 비교해야하고,
hashCode()는 return Objects.hash(iv1, iv2, iv3, ...)를 이용해서 바꾸면 됨.
ex)
import java.util.*;
// equals()와 hashCode()를 오버라이딩 해야 HashSet이 바르게 동작함.
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return name +":"+ age;
}
@Override
public int hashCode() {
// int hash(Object... values); // 가변인자
return Objects.hash(name, age);
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Person)) return false;
Person p = (Person)obj;
// 내 자신(this)의 이름과 나이를 p와 비교
return this.name.equals(p.name) && this.age==p.age;
}
}
public class Ex11_11 {
public static void main(String[] args) {
HashSet set = new HashSet();
set.add("abc");
set.add("abc");
set.add(new Person("David", 10));
set.add(new Person("David", 10));
System.out.println(set);
}
}
ex)
import java.util.*;
public class Ex11_12 {
public static void main(String[] args) {
HashSet setA = new HashSet();
HashSet setB = new HashSet();
HashSet setHab = new HashSet();
HashSet setKyo = new HashSet();
HashSet setCha = new HashSet();
setA.add("1"); setA.add("2"); setA.add("3");
setA.add("4"); setA.add("5");
System.out.println("A = "+setA);
setB.add("4"); setB.add("5"); setB.add("6");
setB.add("7"); setB.add("8");
System.out.println("B = "+setB);
Iterator it = setB.iterator();
// setA.retainAll(setB); // 교집합. 공통된 요소만 남기고 삭제
// setA.addAll(setB); // 합집합. setB의 모든 요소를 추가(중복 제외)
setA.removeAll(setB); // 차집합. setB와 공통 요소를 제거
System.out.println(setA);
}
}
⦁ TreeSet – 범위 탐색, 정렬
- 이진 탐색 트리(binary search tree)로 구현. 범위 탐색과 정렬에 유리.
- 이진 트리는 모든 노드가 최대 2개(0~2개)의 하위 노드를 갖음
각 요소(node)가 나무(tree)형태로 연결(LinkedList의 변형)
class TreeNode {
TreeNode left; // 왼쪽 자식노드
Object element; // 저장할 객체
TreeNode right; // 오른쪽 자식노드
}

⦁ 이진 탐색 트리(binary search tree)
- 부모보다 작은 값은 왼쪽, 큰 값은 오른쪽에 저장
- 데이터가 많아질수록 추가,삭제에 시간이 더 걸림(비교 횟수 증가)

⦁ TreeSet의 데이터 저장과정
HashSet은 equals(), hashCode()로 가지고 있는 데이터와 비교
TreeSet은 compare()를 호출해서 가지고 있는 데이터와 비교
TreeSet에 7,4,9,1,5의 순서로 데이터를 저장하면, 아래의 과정을 거친다.
(루트부터 트리를 따라 내려가며 값을 비교. 작으면 왼쪽, 크면 오른쪽에 저장)

⦁ TreeSet – 주요 생성자와 메소드

(이 외에 Collection 인터페이스가 가지고 있는 메소드도 갖고 있음)
* first() : 제일 작은 객체 반환 / last() : 제일 큰 객체 반환
ex)
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class Ex11_13 {
public static void main(String[] args) {
Set set = new TreeSet(); // 범위 검색, 정렬에 유리. 따로 정렬이 필요없음.
// Set set = new HashSet(); // 정렬 필요
for (int i=0; set.size() < 6; i++) {
int num = (int)(Math.random()*45)+1;
set.add(num); // set.add(new Integer(num));
}
System.out.println(set);
}
}
* TreeSet 객체를 생성할 때 비교 기준을 넣어주든지, 또는 TreeSet에 들어가는 객체가 비교 기준을 갖고 있어야 TreeSet에 저장될 수 있다.
즉, 비교기준이 꼭 필요하다.
ex) from to
import java.util.TreeSet;
public class Ex11_14 {
public static void main(String[] args) {
TreeSet set = new TreeSet(); // 범위 검색에 유리.(from~to)
String from = "b";
String to = "d";
set.add("abc"); set.add("alien"); set.add("bat");
set.add("car"); set.add("Car"); set.add("disc");
set.add("dance"); set.add("dZZZZ"); set.add("dzzzz");
set.add("elephant"); set.add("elevator"); set.add("fan");
set.add("flower");
System.out.println(set);
System.out.println("range search : from " +from + " to " + to);
System.out.println("result1 : " + set.subSet(from, to)); // b부터 d사이
System.out.println("result2 : " + set.subSet(from, to + "zzz"));
}
}
ex) headSet, tailSet, subSet
import java.util.TreeSet;
public class Ex11_15 {
public static void main(String[] args) {
TreeSet set = new TreeSet();
int[] score = {80, 95, 50, 35, 45, 65, 10, 100};
for(int i=0; i<score.length; i++)
set.add(new Integer(score[i]));
System.out.println("50보다 작은 값 : " + set.headSet(new Integer(50))); // 50 미만의 값
System.out.println("50보다 큰 값 : " + set.tailSet(new Integer(50))); // 50 이상의 값
System.out.println("40과 80 사이의 값 : " + set.subSet(40, 80));
}
}
* tailSet은 기준이 되는 값도 포함하는 것으로 보임
⦁ 트리 순회(tree traversal)
- 이진 트리의 모든 노드를 한번씩 읽는 것을 트리 순회라고 한다.
- 전위, 중위, 후위 순회법이 있으며 중위 순회하면 오름차순으로 정렬된다.
preorder = 전위순회
postorder = 후위순회
inorder = 중위순회
맨 위의 노드 줄부터 읽는 것 = 레벨순회
⦁ HashMap과 Hashtable – 순서X, 중복(키X,값O)
- Map인터페이스를 구현, 데이터를 키와 값의 쌍으로 저장
- HashMap(동기화X)은 Hashtable(동기화O)의 신버전
▶ HashMap
- Map인터페이스를 구현한 대표적인 컬렉션 클래스
- 순서를 유지하려면, LinkedHashMap클래스를 사용하면 된다.
▶ TreeMap
- 범위 검색과 정렬에 유리한 컬렉션 클래스
- HashMap보다 데이터 추가, 삭제에 시간이 더 걸림
⦁ HashMap의 키(key)와 값(value)
- 해싱(hashing)기법으로 데이터를 저장. 데이터가 많아도 검색이 빠르다.
- Map인터페이스를 구현, 데이터를 키와 값의 쌍으로 저장
HashMap map = new HashMap();
map.put(“myId”, “1234”);
map.put(“asdf”, “1111”);
map.put(“asdf”, “1234”); // 중복된 키가 새로 들어오면 기존에 있던 키와 값이 사라짐
key와 value의 쌍을 Entry 라고 함.
class Entry {
Object key;
Object value;
}
⦁ 해싱(hashing)
- 해쉬함수(hash function)로 해쉬테이블(hash table)에 데이터를 저장, 검색
- 해쉬테이블은 배열과 링크드 리스트가 조합된 형태(2차원 배열이라 table이라고 함)
▶ 해쉬테이블에 저장된 데이터를 가져오는 과정

1) 키로 해쉬함수를 호출해서 해쉬코드(배열의 index)를 얻는다.
2) 해쉬코드(해쉬함수의 반환값)에 대응하는 링크드리스트를 배열에서 찾는다.
3) 링크드리스트에서 키와 일치하는 데이터를 찾는다.
* 해쉬함수는 같은 키에 대해 항상 같은 해쉬코드를 반환해야 한다.
서로 다른 키일지라도 같은 값의 해쉬코드를 반환할 수도 있다.
⦁ HashMap의 주요 메소드
생성자)
HashMap()
HashMap(int initialCapacity)
HashMap(int initialCapacity, float loadFactor)
HashMap(Map m)
메소드)
Object put(Object key, Object value)
void putAll(Map m) // 추가
Object remove(Object key)
Object replace(Object key, Object value) // 변경
boolean replace(Object key, Object oldValue, Object newValue) // 변경
Set entrySet() // 키와 값 쌍을 Set으로 저장
Set keySet() // 키를 저장
Collection values() // 값을 저장
Object get(Object key) // 키를 넣으면 값을 반환
Object getOrDefault(Object key, Object defaultValue) // 키가 없을 때 지정한 값을 반환
boolean containsKey(Object key) // 지정된 키가 있는지
boolean containsValue(Object value) // 지정된 값이 있는지
그 외 : int size() / boolean isEmpty() / void clear() / Object clone()
ex)
import java.util.*;
public class Ex11_16 {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("myId", "1234");
map.put("asdf", "1111");
System.out.println(map);
map.put("asdf", "1234");
System.out.println(map);
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("id와 password를 입력해주세요.");
System.out.print("id :");
String id = sc.nextLine().trim();
System.out.print("password :");
String password = sc.nextLine().trim();
System.out.println();
if(!map.containsKey(id)) {
System.out.println("입력하신 id는 존재하지 않습니다. 다시 입력해주세요.");
continue;
}
if (!(map.get(id)).equals(password)) {
System.out.println("비밀번호가 일치하지 않습니다. 다시 입력해주세요");
} else {
System.out.println("id와 비밀번호가 일치합니다.");
break;
}
}
}
}
ex)
import java.util.*;
public class Ex11_17 {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("김자바", 90);
map.put("김자바", 100);
map.put("이자바", 100);
map.put("강자바", 80);
map.put("안자바", 90);
Set set = map.entrySet();
Iterator it = set.iterator();
while(it.hasNext()) {
Map.Entry e = (Map.Entry)it.next();
System.out.println("이름 : "+e.getKey() + ", 점수 : " + e.getValue());
}
set = map.keySet();
System.out.println("참가자 명단 : " + set);
Collection values = map.values();
it = values.iterator();
int total = 0;
while(it.hasNext()) {
int i = (int)it.next();
total += i;
}
System.out.println("총점 : " + total);
System.out.println("평균 : " + (float)total/set.size());
System.out.println("최고점수 : " + Collections.max(values)); // comparable을 구현한 객체만 들어올 수 있음
System.out.println("최저점수 : " + Collections.min(values)); // comparable을 구현한 객체만 들어올 수 있음
}
}
ex)
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class Ex11_18 {
public static void main(String[] args) {
String[] data = {"A","K","A","K","D","K","A","K","K","K","Z","D"};
HashMap map = new HashMap();
for(int i=0; i<data.length; i++) {
if (map.containsKey(data[i])) {
int value = (int)map.get(data[i]);
map.put(data[i], value+1); // 기존에 존재하는 키면 기존값을 1 증가시킴
} else {
map.put(data[i], 1); // 기존에 존재하지 않는 키는 값을 1로 저장
}
}
Iterator it = map.entrySet().iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
int value = (int)entry.getValue();
System.out.println(entry.getKey() + " : " + printBar('#', value)+" "+value);
}
}
public static String printBar(char ch, int value) {
char[] bar = new char[value];
for(int i=0; i<bar.length; i++)
bar[i] = ch;
return new String(bar); // String(char[] chArr)
}
}
⦁ Collections – 컬렉션을 위한 메소드(static)를 제공
(Objects는 객체, Arrays는 배열, Collections는 컬렉션을 다룰 때 사용하는 클래스)
1. 컬렉션 채우기, 복사, 정렬, 검색 – fill(), copy(), sort(), binarySearch() 등
2. 컬렉션의 동기화 – synchronizedXXX()
static Collection synchronizedCollection(Collection c)
static List synchronizedList(List list)
static Set synchronizedSet(Set s)
static Map synchronizedMap(Map m)
static SortedSet synchronizedSortedSet(SortedSet s)
static SortedMap synchronizedSortedMap(SortedMap m)
List syncList = Collections.synchronizedList(new ArrayList(...));
(동기화된 list는 Vector와 유사)
3. 변경불가(readOnly) 컬렉션 만들기 – unmodifiableXXX()
static Collection unmodifiableCollection(Collection c)
static List unmodifiableList(List list)
static Set unmodifiableSet(Set s)
static Map unmodifiableMap(Map m)
static NavigableSet unmodifiableNavigableSet(NavigableSet s)
static SortedSet unmodifiableSortedSet(SortedSet s)
static NavigableMap unmodifiableNavigableMap(NavigableMap m)
static SortedMap unmodifiableSortedMap(SortedMap m)
4. 싱글톤 컬렉션 만들기 – singletonXXX() 객체 1개만 저장
static List singletonList(Object o)
static Set singleton(Object o) // singletonSet이 아님에 주의
static Map singletonMap(Object key, Object value)
5. 한 종류의 객체만 저장하는 컬렉션 만들기 – checkedXXX()
static Collection checkedCollection(Collection c, Class type)
static List checkedList(List list, Class type)
static Set checkedSet(Set s, Class type)
static Map checkedMap(Map m, Class keyType, Class valueType)
static Queue checkedQueue(Queue queue, Class type)
static NavigableSet checkedNavigableSet(NavigableSet s, Class type)
static SortedSet checkedSortedSet(SortedSet s, Class type)
static NavigableMap checkedNavigableMap(NavigableMap m, Class keyType, Class valueType)
static SortedMap checkedSortedMap(SortedMap m, Class keyType, Class valueType)
ex) String만 저장하는 checkedList
List list = new ArrayList();
List checkedList = checkedList(list, String.class); // String만 저장가능
checkedList.add(“abc”); // OK
checkedList.add(new Integer(3)); // 에러, ClassCastException발생
ex)
import static java.util.Collections.*; // Collections를 생략가능하게 해준다.
import java.util.*;
public class Ex11_19 {
public static void main(String[] args) {
List list = new ArrayList();
System.out.println(list);
addAll(list, 1,2,3,4,5);
System.out.println(list);
rotate(list, 2); // 반시계방향으로 두 번 회전
System.out.println(list);
swap(list, 0, 2); // 첫 번째와 세 번째를 교환(swap)
System.out.println(list);
shuffle(list); // 저장된 요소의 위치를 임의로 변경
System.out.println(list);
sort(list, reverseOrder()); // 역순 정렬 reverse(list);와 동일
System.out.println(list);
sort(list); // 정렬
System.out.println(list);
int idx = binarySearch(list, 3); // 3이 저장된 위치(index)를 반환
System.out.println("index of 3 = " + idx);
System.out.println("max="+max(list));
System.out.println("min="+min(list));
System.out.println("min="+max(list, reverseOrder()));
fill(list,9); // list를 9로 채운다.
System.out.println("list="+list);
// list와 같은 크기의 새로운 list를 생성하고 2로 채운다. 단, 결과는 변경불가
List newList = nCopies(list.size(), 2);
System.out.println("newList="+newList);
System.out.println(disjoint(list, newList)); // 공통요소가 없으면 true
copy(list, newList); // list를 newList과 같게 복사
System.out.println("newList="+newList);
System.out.println("list="+list);
replaceAll(list, 2, 1); // list의 2를 전부 1로 변환
System.out.println("list="+list);
Enumeration e = enumeration(list);
ArrayList list2 = list(e);
System.out.println("list2="+list2);
}
}
출처 - 유튜브 남궁성의 정석코딩 [자바의 정석 - 기초편]
'Java > Java의 정석' 카테고리의 다른 글
220324 Java - Chapter 12. 지네릭스, 열거형, 애너테이션 Part.2 (0) | 2022.03.24 |
---|---|
220323 Java - Chapter.12 지네릭스, 열거형, 애너테이션 Part.1 (0) | 2022.03.23 |
220321 Java - Chapter.11 Collections Framework Part.2 (0) | 2022.03.21 |
220319 Java - Chapter 11. Collections Framework Part.1 (0) | 2022.03.19 |
220316 Java - Chapter 10. 날짜와 시간 & 형식화 (0) | 2022.03.17 |