August 29, 2020
List
Set
Map
Collection인터페이스
를 정의(Map은 성격이 약간 달라서)객체 배열이므로 모든 종류의 객체 저장 가능하다.(Vector도 마찬가지)
String의 “1”과 new Integer(1)은 다르다.
ArrayList list1 = new ArrayList(); // 크기 10인 ArrayList생성
list1.add(5); // 이것은 사실 list1.add(new Integer(5)); // autoboxing에 의해 기본형이 참조형으로 자동 변환
public class Vector extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable
{
...
protected Object[] elementData; // 객체를 담기 위한 배열
...
}
ArrayList의 메서드
ArrayList list1 = new ArrayList();
...(중략)...
list.remove(1); //인덱스가 1인 객체를 삭제
ArrayList list1 = new ArrayList();
...(중략)...
list.remove(new Integer(1)); // 1을 삭제
ArrayList에 저장된 첫 객체부터 삭제하는 경우(배열 복사 발생)
data[0]=0 data[1]=1 data[2]=2 data[3]=3 data[4]=4 data[5]=null data[6]=null
for(int i = 0; i<list.size(); i++)
list.remove(i);
위와 같은 방식으로 하면 다 지우지 못한다. 왜냐하면 하나씩 지울때마다 뒤의 배열들이 복사되어 앞으로 당겨지기 때문이다.
ArrayList에 저장된 마지막 객체부터 삭제하는 경우(배열 복사 발생안함) data[0]=0 data[1]=1 data[2]=2 data[3]=3 data[4]=4 data[5]=null data[6]=null
for(int i = list.size() - 1; i>=0; i--)
list.remove(i);
위와 같은 방식으로는 배열 복사가 일어나지 않고 마지막 객체부터 하나씩 다 지워나갈 수 있다.
장점
단점
기차
로 비유Node
라고 한다. 각 Node는 데이터와 다음노드의 주소값을 가지고 있다.데이터 삭제
데이터 추가
단점
기차
로 비유하자면 1칸->3칸으로 이동하려면 반드시 2칸을 거쳐야 한다. 그리고 2칸에서 1칸으로(반대로) 접근하지 못한다. 더블리 링크드 리스트(doubly linked list), 이중 연결리스트
는 이 단점을 보완해서 각 Node의 앞, 뒤로 이동 가능(그러나 여전히 여러칸을 한번에 뛰어넘지는 못한다). 더블리 써큘러 링크드 리스트(double circular linked list), 이중 원형 연결리스트
는 한 번 더 이 단점을 보완한 것.순차적으로 데이터를 추가/삭제
비순차적으로 데이터를 추가/삭제
주요 메서드
객체를 저장하기 전에 기존에 같은 객체가 있는지 확인. 같은 객체가 없으면 저장하고, 있으면 저장하지 않는다.
public class test {
public static void main(String[] args) {
HashSet set = new HashSet();
set.add("abc");
set.add("abc"); //중복이라 저장안됨
set.add(new Person("June", 10));
set.add(new Person("June", 10));
System.out.println(set);
}
}
class Person {
String name;
int age;
@Override
public int hashCode() {
return Objects.hash(name, age); //Objects라는 클래스 사용
// return (name + age).hashcode(); //원래는 이런식으로 했다. (name+age)가 String이므로 String 클래스의 hashcode() 부른 것이었음.
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Person)) return false;
//Person객체가 아니면 비교할 필요도 없으므로
Person p = (Person)obj;
//형변환해서 접근리모콘 만들어야 밑에서 p.name과 p.age로 사용할 수 있으니.
return name.equals(p.name) && age==p.age;
// iv들(name, age)을 각각 비교한 것.
//위의 것은 사실 this.이 생략된 것. 객체 자신(this)과 매개변수로 지정된 객체(obj)를 비교하는 것이다.
return this.name.equals(p.name) && this.age==p.age;
}
Person(String name, int age){
this.name = name;
this.age = age;
}
public String toString() {
return name + ":" + age;
}
}
class TreeNode {
TreeNode left; // 왼쪽 자식노드
Object element; // 저장할 객체
TreeNode right; // 오른쪽 자식노드
}
이진 탐색 트리
단점
root부터 시작해서
부모까지 다 비교해서 대소를 비교해서 적정자리에 저장, 삭제해야 하므로데이터 저장과정 boolean add(Object o)
해싱(hashing)기법으로 해시테이블(hash table)에 데이터를 저장. 데이터가 많아도 검색이 빠르다.
미리 존재해 있는 키 값을 넣으면 늦게 입력한 키, 값이 덮어쓴다.
entry
라고 한다.해시테이블에 저장된 데이터를 가져오는 과정
주요 메서드
예제1
public class test {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("june", "1234");
map.put("min", "1111");
map.put("heo", "1234");
Scanner s = new Scanner(System.in);
while(true) {
System.out.println("id와 password를 입력해보세요");
System.out.println("Id : ");
String id = s.nextLine().trim();
System.out.println("password : ");
String password = s.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;
}
}
}
}
예제2
public class test {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("가", new Integer(90));
map.put("나", new Integer(100));
map.put("다", new Integer(30));
map.put("라", new Integer(40));
map.put("마", new Integer(50));
Set set = map.entrySet();
Iterator it = set.iterator();
while(it.hasNext()) {
Map.Entry e = (Map.Entry)it.next(); //Entry는 Map인터페이스 안에 정의된 내부 인터페이스
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)); //max안에는 comparable을 구현한 객체만 들어올 수 있다(기준이 있어야 하므로). 밑의 min도 마찬가지
System.out.println("최저점수 : " + Collections.min(values));
}
}
결과는
이름 : 가, 점수 : 90
이름 : 다, 점수 : 30
이름 : 나, 점수 : 100
이름 : 마, 점수 : 50
이름 : 라, 점수 : 40
참가자 명단 : [가, 다, 나, 마, 라]
총점 : 310
평균 : 62.0
최고점수 : 100
최저점수 : 30
메서드
확인
만꺼내기
스택의 활용
인터페이스(객체 생성 안됨)
메서드
큐의 활용
public class Test {
public static void main(String[] args) {
Stack st = new Stack();
Queue q = new LinkedList(); //Queue 인터페이스 구현체인 LinkedList
st.push("0");
st.push("1");
st.push("2");
q.offer("0");
q.offer("1");
q.offer("2");
System.out.println("= Stack = ");
while(!st.empty()) {
System.out.println(st.pop()); // 스택에서 요소 하나를 꺼냄
}
System.out.println("= Queue = ");
while(!q.isEmpty()) {
System.out.println(q.poll());
}
}
}
그럼 결과는
= Stack =
2
1
0
= Queue =
0
1
2
Iterator
를 사용하기Iterator의 핵심 메서드 2개
Enumeration의 핵심 메서드 2개
표준화
한 것이다. 그래서 구조(List, Set, Map)가 어떻든 간에 hasNext()와 next()로 접근하여 사용하면 된다.사용법
List list = new ArrayList(); // 다른 컬렉션으로 변경할 때는 이 이 부분만 고치면 된다.
Iterator it = list.iterator();
while(it.hasNext()){ //boolean hasNext() 읽어올 요소가 있는지 확인
System.out.println(it.next()); // Object next() 다음 요소를 읽어옴
}
public interface Collection {
...
public Iterator iterator();
...
}
public class test {
public static void main(String[] args) {
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
Iterator it = list.iterator();
while(it.hasNext()) {
Object obj = it.next(); // 읽음
System.out.println(obj);
}
}
}
결과는?
1
2
3
4
5
public class Ex11_5 {
public static void main(String[] args) {
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
Iterator it = list.iterator(); //1회용임
while(it.hasNext()) {
Object obj = it.next(); // 읽음
System.out.println(obj);
}
Iterator it = list.iterator();
while(it.hasNext()) { // false가 된다.
Object obj = it.next();
System.out.println(obj);
}
}
}
결과는
1
2
3
4
5
Map에는 iterator()가 없다. 그래서 keySet(), entrySet(), values()를 호출해야 한다. 각각의 반환타입은 Set, Set, Collection이다. Map을 통해서 바로 iterator()를 가져오지 않고 이들을(KeySet(), entrySet(), values()) 통해서 Set이나 Collection을 얻은 다음에 이를 통해 iterator() 호출
Map map = new HashMap();
...
Iterator it = map.entrySet().iterator();
위의 두번째 줄은 사실 아래와 같다.
Set eSet = map.entrySet();
Iterator it = eSet.iterator();
배열의 복사 - copyOf(), copyOfRange()
배열 채우기 - fill(), setAll()
int[] arr = new int[5];
Arrays.fill(arr, 9);
Arrays.setAll(arr, (i) -> (int)(Math.random()*5+1); // arr = [1, 5, 2, 1, 1]
배열의 정렬과 검색 - sort(), binarySearch()
int[] arr = {3, 2, 0, 1, 4};
int idx = Arrays.binarySearch(arr, 2);
Arrays.sort(arr); //정렬
System.out.println(Arrays.toString(arr)); //[0, 1, 2, 3, 4]
int idx = Arrays.binarySearch(arr, 2); //idx=2
다차원 배열의 출력 - deepToString()
int[] arr = {0, 1, 2, 3, 4};
int[][] arr2D = {{11, 12}, {21, 22}};
System.out.println(Arrays.toString(arr)); // {0, 1, 2, 3, 4}
System.out.println(Arrays.deepToString(arr)); //{{11, 12}, {21, 22}};
컬렉션의 동기화 - synchronizedXXX()
static Collection synchronized
Collection(Collection c)
static List synchronized
List(List list)
static Set synchronized
Set(Set s)
static Map synchronized
Map(Map m)
static SortedSet synchronized
SortedSet(SortedSet s)
static SortedSet synchronized
SortedMap(SortedMap m)
매개변수인(동기화X) new ArrayList 를 넣어서 동기화 된 synList를 만드는 것
동기화된 synList는 Vector(원래 동기화O)와 동일해지게 된 것
List synList = Collections.synchronizedList(new ArrayList(...));
변경불가(readOnly) 컬렉션 만들기 - unmodifiableXXX()
static Collection unmodifiable
Collection(Collection c)
static List unmodifiable
List(List list)
static Set unmodifiable
Set(Set s)
static Map unmodifiable
Map(Map m)
static NavigableSet unmodifiable
NavigableSet(NavigableSet s)
static SortedSet unmodifiable
SortedSet(SortedSet s)
static NavigableMap unmodifiable
NavigableMap(NavigableMap m)
static SortedMap unmodifiable
SortedMap(SortedMap m)
싱글톤 컬렉션 만들기 - singletonXXX()
static List singleton(Object o)
static Set singleton(Object o)
static Map singletonMap(Object key, Object value)
한 종류의 객체만 저장하는 컬렉션 만들기 - checkedXXX()
static Collection checked
Collection(Collection c, Class type)
static List checked
List(List list, Class type)
static Set checked
Set(Set s, Class type)
static Map checked
Map(Map m, Class keyType, Class valueType)
static Queue checked
Queue(Queue queue, Class type)
static NavigableSet checked
NavigableSet(NavigableSet s, Class type)
static SortedSet checked
SortedSet(SortedSet s, Class type)
static NavigableSet checked
NavigableMap(NavigableMap m, Class keyType, class valueType)
static SortedMap checked
SortedMap(SortedMap m, Class keyType, Class valueType)
원래 add(Object obj)라서 다 넣을 수 있지만 지정한 종류의 타입만 가능
List list - new ArrayList();
List CheckedList = checkedList(list, String.class); // String만 저장가능
checkedList.add("abc");
checkedList.add(new Integer(3)); //에러남 ClassCastException 발생
객체 정렬에 필요한 메서드(정렬기준 제공)를 정의한 인터페이스
public interface Comparator {
int compare(Object o1, Object o2) // o1, o2 두 객체를 비교. 0이면 같고 양수면 왼쪽이 큰 것이고 음수면 반대
boolean equals(Object obj); //equals를 오버라이딩하라는 뜻
}
public interface Comparable {
int compareTo(Object o); //주어진 객체(o)를 자신(this)과 비교
}
compare()와 compareTo()는 두 객체의 비교결과를 반환하도록 작성. 같으면 0, 오른쪽이 크면 음수(-), 작으면 양수(+)
public final class Integer extends Number implements Comparable {
...
public int compareTo(Integer anotherInteger) {
int v1 = this.value;
int v2 = anotherInteger.value;
//같으면 0, 오른쪽 값이 크면 -1, 작으면 1을 반환
return (v1 < v2 ? -1 : (v1==v2 ? 0 : 1));
}
}
두 대상을 비교하고 자리를 바꾼다.
이 부분은 절대불변이며(버블정렬, 선택정렬 등 모두 다 동일), 우리는 그 정렬하는 기준만 제시해주면 되는 것이다. 절대불변인 구체적 방법은 이미 다 구현되어 있는 상태.참고 : 자바의 정석 - 남궁성