4 분 소요

컬렉션 프레임워크

컬렉션 프레임워크는 다양한 인터페이스로 구분되어 있다. 그 중 가장 많이 사용되는 인터페이스는 Collection 인터페이스와 Map 인터페이스가 있다. Collection 인터페이스는 하나의 자료를 모아서 관리하는데 사용되며 크게 List 프레임워크와 Set 프레임워크로 구분되어있다. Map 프레임워크는 쌍으로 된 자료들을 관리하는데 유용하다.

Collection 인터페이스

  • List 인터페이스 : 순서가 있는 자료 관리, 중복 혀용, ArrayList, Vector, LinkedList 클래스 등
  • Set 인터페이스 : 순서가 정해지지 않음, 중복 허용 X, HashSet, TreeSet 클래스 등

Collection에 객체를 추가하기 위해서는 add() 메서드를 사용한다. 백준 문제를 풀 때, 어떤거는 put() 을 사용하고, 어떤거는 add() 를 사용하는 것은 인터페이스의 차이로 발생하는 것이었다.

Map 인터페이스

key - value로 이루어져 있다.

Hashtable, HashMap, TreeMap 클래스 등

  • key : 중복될 수 없고 유일하게 딱 하나인 값
  • value : 중복될 수 있고, 여러 개의 값일 수도 있다.

Collection 인터페이스 -> List 인터페이스 -> ArrayList 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//Member.java -> 회원의 아이디와 이름을 가져옴
package collection;
 
public class Member {
    private int memberId;
    private String memberName;
 
    public Member(int memberId, String memberName) {
        this.memberId = memberId;
        this.memberName = memberName;
    }
 
    public int getMemberId() {
        return memberId;
    }
 
    public void setMemberId(int memberId) {
        this.memberId = memberId;
    }
 
    public String getMemberName() {
        return memberName;
    }
 
    public void setMemberName(String memberName) {
        this.memberName = memberName;
    }
 
    @Override
    public String toString() {
        return memberName + " 회원님의 아이디는 " + memberId + "입니다.";
    }
}
 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//MemberArrayList.java -> Member 데이터형을 가진 변수를 ArrayList를 만들어서 추가시켜줌
package collection.arraylist;
 
import java.util.ArrayList;
import collection.Member; //컬랙션 패키지의 Member 클래스 임포트
 
public class MemberArrayList {
    private ArrayList<Member> arrayList;
 
    public MemberArrayList() {
        arrayList = new ArrayList<Member>();
    }
 
    public void addMember(Member member) {
        arrayList.add(member);
        System.out.println(member.toString());
    }
 
    public boolean removeMember(int memberId) {
        for (int i = 0; i < arrayList.size(); i++) {
            Member member = arrayList.get(i);
            int tempId = member.getMemberId();
            if (tempId == memberId) {
                arrayList.remove(i);
                return true;
            }
        }
        System.out.println(memberId + "가 존재하지 않습니다.");
        return false;
    }
 
    public void showAllMember() {
        for (Member member : arrayList) {
            System.out.println(member);
        }
        System.out.println();
    }
}
 
 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//MemberArrayListTest.java
package collection.arraylist;
 
import collection.Member;
 
public class MemberArrayListTest {
 
    public static void main(String[] args) {
        MemberArrayList memberArrayList = new MemberArrayList();
        //각 회원의 아이디와 이름을 넣은 변수 Member형
        Member memberLee = new Member(1001"이지원");
        Member memberSon = new Member(1002"손민국");
        Member memberPark = new Member(1003"박서훤");
        Member memberHong = new Member(1004"홍길동");
        
        //Member형 데이터들을 추가시키는 메서드 addMember
        memberArrayList.addMember(memberLee);
        memberArrayList.addMember(memberSon);
        memberArrayList.addMember(memberPark);
        memberArrayList.addMember(memberHong);
        
        memberArrayList.showAllMember();
        
        memberArrayList.removeMember(memberHong.getMemberId());
        memberArrayList.showAllMember();
        
    }
 
}
 
cs
  • Member.java : 회원의 아이디와 이름을 받는 클래스
  • MemberArrayList.java : Member형을 ArrayList에 추가하는 클래스
  • MemberArrayListTest.java : 테스트

Collection 인터페이스 -> List 인터페이스 -> ArrayList VS Vector

가장 큰 차이는 동기화 지원 여부이다. 동기화란 두개 이상의 스레드가 동시에 Vector을 사용할 때 오류가 나지 않도록 실행 순서를 보장한다. 여기서 스레드란 작업 단위이다. 하나의 스레드만을 수행하는 것을 단일 스레드라고 한다. 단일 스레드를 사용하는 것이라면 ArrayList를 사용하는 것이 좋다. 하지만 멀티스레트가 실행되는 경우, 스레드가 동시에 실행되면 같은 메모리 공간에 접근하기 때문에 메모리상 오류가 발생할 수 있다. 이때 메모리에 동시에 접근하지 못하도록 순서를 맞추는 것이 동기화이다. 동기화를 구현하기 위해서는 동시에 작업이 이루어 질 수 있는 데이터에 대해 잠금을 수행한다. 그리고 수행이 끝나면 잠금을 해제하는데, 이럴때마다 시간이 너무 오래걸리기 때문에 단일 스레드라면 ArrayList 사용을 권장하는 것이다.

두번째로 다른 점은 배열은 생성할 때, 용량을 지정하고, 용량보다 더 많은 요소가 추가된 경우에는 용량을 늘려가며 수행해야 된다. 용량을 늘리기 위해서는 더 큰 배열에 요소들을 복사해야되는 번거로움이 있다. 하지만 LinkedList 같은 경우에는 동적으로 요소의 메모리를 생성이 가능하고, 중간에 요소를 추가하거나 제거하는데 편리함이 있다. 따라서 자료의 변동이 많은 경우에는 링크드 리스트를, 자료 변동이 거의 없는 경우에는 배열을 사용하는 것이 효율적이다.

Collection 인터페이스 -> List 인터페이스 -> LinkedList 클래스

링크드인 이유는 각 요소에 다음 요소를 가리키는 주소값이 있기 때문이다.

Ex. **A B의 주소 -> B D의 주소 -> D null -> null**



  • 요소 추가하기

배열이라면 중간에 요소를 추가하기 위해서 추가할 자리의 요소를 비워서 그 자리에 새로운 요소를 넣어야 한다. 하지만 LinkedList 클래스의 경우는 주소값만 변경시켜주면 된다.

  • 요소 제거하기

제거하는 방법도 마찬가지로 요소가 가리키는 주소값만 변경시켜주면 된다.

  • LinkedList 클래스 활용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package collection;
 
import java.util.LinkedList;
 
public class LinkedListTest {
 
    public static void main(String[] args) {
        LinkedList<String> myList = new LinkedList<>();
        
        myList.add("A");
        myList.add("B");
        myList.add("C");
        
        System.out.println(myList); //[A, B, C]
        
        myList.add(1"D"); //링크드 첫 번째 위치에 D를 추가
        System.out.println(myList); //[A, D, B, C]
        
        myList.addFirst("0");
        System.out.println(myList); //[0, A, D, B, C]
        
        System.out.println(myList.removeLast()); //C
        System.out.println(myList); //[0, A, D, B]
    }
 
}
 
cs

LinkedList 클래스에는 addFrist(), addLast(), removeFrist(), removeLast() 가 있다.

ArrayList로 스택과 큐 구현하기

스택은 백준 문제를 풀면서도 사용한 적이 있다. 스택이란 상자를 올리는 것처럼 맨 나중에 추가된 데이터를 가장 먼저 꺼내는 방식을 가지고 있는 자료 구조이다. 큐는 먼저 추가된 데이터먼저 꺼내서 사용하는 방식을 가지고 있는 자료 구조이다.

  • 스택 구현
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package collection.arraylist;
 
import java.util.ArrayList;
 
class MyStack {
    private ArrayList<String> arrayStack = new ArrayList<String>();
    
    public void push(String data) {
        arrayStack.add(data);
    }
    
    public String pop() {
        int len = arrayStack.size();
        if (len == 0) {
            System.out.println("스택이 비었습니다.");
            return null;
        }
        
        return(arrayStack.remove(len - 1));
    }
}
 
public class StackTest {
 
    public static void main(String[] args) {
        
        MyStack stack = new MyStack();
        stack.push("A");
        stack.push("B");
        stack.push("C");
        
        System.out.println(stack.pop()); //C
        System.out.println(stack.pop()); //B
        System.out.println(stack.pop()); //A
    }
 
}
 
cs


  • 큐 구현
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package collection.arraylist;
 
import java.util.ArrayList;
 
class MyQueue {
    private ArrayList<String> arrayQueue = new ArrayList<>();
    
    public void enQueue(String data) {
        arrayQueue.add(data);
    }
    
    public String deQueue() {
        int len = arrayQueue.size();
        
        if(len == 0) {
            System.out.println("큐가 비었습니다.");
            return null;
        }
        
        return (arrayQueue.remove(0));
    }
}
 
public class QueueTest {
 
    public static void main(String[] args) {
        
        MyQueue queue = new MyQueue();
        
        queue.enQueue("A");
        queue.enQueue("B");
        queue.enQueue("C");
        
        System.out.println(queue.deQueue()); //A
        System.out.println(queue.deQueue()); //B
        System.out.println(queue.deQueue()); //C
    }
 
}
 
cs



Collection 요소를 순회하는 Iterator

Set 인터페이스같은 경우는 순서가 없기 때문에 ArrayList 처럼 반복문과 get(i)를 통해서 값을 가져올 수 없다. 이때 사용해야되는 인터페이스가 Iterator 이다. Iterator같은 경우는 Collection 인터페이스를 사용하여 만든 ArrayList, Set 인터페이스에서 Iterator() 메서드를 호출하면 Iterator 클래스가 반환되므로 Iterator형 변수에 대입해 사용한다.

  • boolean hashNext() : 이후에 요소가 더 있는지를 체크하는 메서드
  • E next() : 다음에 있는 요소를 반환, 제네릭 자료형을 사용하여 Iterator가 순회할 요소의 자료형을 지정

Collection 인터페이스 -> Set 인터페이스

순서와 상관없이 중복을 허용하지 않는 경우에 사용한다. Set 인터페이스를 구현한 대표 클래스에는 HashSetTreeSet 이 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package collection.hashset;
 
import java.util.HashSet;
 
public class HashSetTest {
 
    public static void main(String[] args) {
        
        HashSet<String> hashSet = new HashSet<String>();
        hashSet.add(new String("임정순"));
        hashSet.add(new String("박현정"));
        hashSet.add(new String("홍연의"));
        hashSet.add(new String("강감찬"));
        hashSet.add(new String("강감찬"));
        
        System.out.println(hashSet); //[홍연의, 박현정, 강감찬, 임정순]
 
    }
 
}
 
cs

중복을 허용하지 않는 것을 볼 수 있다.

Colleciton 인터페이스 -> Set 인터페이스 -> HashSet 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//MemberHashSet.java -> hashSet을 이용해서 멤버 지우기 
package collection.hashset;
 
import java.util.HashSet;
import java.util.Iterator;
 
import collection.Member;
 
public class MemberHashSet {
    
    private HashSet<Member> hashSet;
    
    public MemberHashSet() {
        hashSet = new HashSet<Member>();
    }
    
    public void addMember(Member member) {
        hashSet.add(member);
    }
    
    public boolean removeMember(int memberId) {
        Iterator<Member> ir = hashSet.iterator(); //Set 인터페이스는 순서가 없기 때문에 get()메서드를 사용할 수 없다. 
        while (ir.hasNext()) {
            Member member = ir.next();
            int tempId = member.getMemberId();
            if (tempId == memberId) {
                hashSet.remove(member);
                return true;
            }
        }
        System.out.println(memberId + "가 존재하지 않습니다.");
        return false;
    }
    
    public void showAllMember() {
        for (Member member : hashSet) {
            System.out.println(member);
        }
        System.out.println();
    }
}
 
cs

Iterator 사용 ! Set 인터페이스는 순서가 없기 때문에 get() 메서드 사용 불가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//MemberHashSetTest.java
package collection.hashset;
 
import collection.Member;
 
public class MemberHashSetTest {
 
    public static void main(String[] args) {
        
        MemberHashSet memberHashSet = new MemberHashSet();
        
        Member memberLee = new Member(1001"이지원");
        Member memberSon = new Member(1002"손민국");
        Member memberPark = new Member(1003"박서훤");
        
        memberHashSet.addMember(memberLee);
        memberHashSet.addMember(memberSon);
        memberHashSet.addMember(memberPark);
        memberHashSet.showAllMember();
        /*
        손민국 회원님의 아이디는 1002입니다.
        이지원 회원님의 아이디는 1001입니다.
        박서훤 회원님의 아이디는 1003입니다.
         */
        
        Member memberHong = new Member(1003"홍길동");
        memberHashSet.addMember(memberHong);
        memberHashSet.showAllMember();
        /*
        손민국 회원님의 아이디는 1002입니다.
        홍길동 회원님의 아이디는 1003입니다.
        이지원 회원님의 아이디는 1001입니다.
        박서훤 회원님의 아이디는 1003입니다.
         */
    }
 
}
 
cs

Set 인터페이스를 사용했다면 중복이 발생하면 안되는데, 지금 아이디 값 중복이 발생! 그 이유는 일반적으로 Set에서 다르다고 판단되는 것은 인스턴스의 주소가 다른 경우이다. 하지만 우리는 아이디가 다른 값만 넣어야 하므로 equals()hashCode() 메서드를 재정의 해야된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Member.java -> 회원의 아이디와 이름을 가져옴
package collection;
 
public class Member {
    private int memberId;
    private String memberName;
    
    ...
 
 
    @Override
    public int hashCode() {
        return memberId;
    }
    
    @Override
    public boolean equals(Object obj) {
        if(obj instanceof Member) {
            Member member = (Member)obj;
            if (this.memberId == member.memberId) { //매개 변수로 받은 회원 아이디가 자신의 회원 아이디와 같다면 true 리턴
                return true;
            }
            else {
                return false;
            }
        }
        return false;
    }
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//MemberHashSetTest.java -> Member.java 재정의 후
package collection.hashset;
 
import collection.Member;
 
public class MemberHashSetTest {
 
    public static void main(String[] args) {
        
        MemberHashSet memberHashSet = new MemberHashSet();
        
        Member memberLee = new Member(1001"이지원");
        Member memberSon = new Member(1002"손민국");
        Member memberPark = new Member(1003"박서훤");
        
        memberHashSet.addMember(memberLee);
        memberHashSet.addMember(memberSon);
        memberHashSet.addMember(memberPark);
        memberHashSet.showAllMember();
        /*
        손민국 회원님의 아이디는 1002입니다.
        이지원 회원님의 아이디는 1001입니다.
        박서훤 회원님의 아이디는 1003입니다.
         */
        
        Member memberHong = new Member(1003"홍길동");
        memberHashSet.addMember(memberHong);
        memberHashSet.showAllMember();
        /*
        손민국 회원님의 아이디는 1002입니다.
        이지원 회원님의 아이디는 1001입니다.
        박서훤 회원님의 아이디는 1003입니다.
         */
    }
 
}
 
cs

수정 된 것을 확인 할 수 있다.

Collection 인터페이스 -> Set 인터페이스 -> TreeSet 클래스

Collection 인터페이스나 Map 인터페이스를 구현한 클래스 중 Tree로 시작하는 클래스는 데이터를 추가한 후 결과를 출력하면 결과 값이 정렬된다. TreeSet은 자료의 중복ㅇ르 허용하지 않으면서 출력 결과 값을 정렬하는 클래스이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package collection.hashset;
 
import java.util.TreeSet;
 
public class TreeSetTest {
 
    public static void main(String[] args) {
        
        TreeSet<String> treeSet = new TreeSet<String>();
        treeSet.add("이순신");
        treeSet.add("강감찬");
        treeSet.add("홍길동");
        
        for (String str : treeSet) {
            System.out.println(str);
            
            /*
             강감찬
             이순신
             홍길동
             */
        }
    }
 
}
 
cs

출력 결과 값들이 정렬되어 있는 것을 확인할 수 있다.



TreeSet 활용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//MemberTreeSet.java
package collection.treeset;
 
import java.util.Iterator;
import java.util.TreeSet;
 
import collection.Member;
 
public class MemberTreeSet {
    private TreeSet<Member> treeSet;
    
    public MemberTreeSet() {
        treeSet = new TreeSet<Member>();
    }
    
    public void addMember(Member member) {
        treeSet.add(member);
    }
    
    public boolean removeMember(int memberId) {
        Iterator<Member> ir = treeSet.iterator();
        
        while (ir.hasNext()) {
            Member member = ir.next();
            int tempId = member.getMemberId();
            if (tempId == memberId) {
                treeSet.remove(member);
                return true;
            }
        }
        System.out.println(memberId + "가 존재하지 않습니다.");
        return false;
    }
    
    public void showAllMember() {
        for (Member member : treeSet) {
            System.out.println(member);
        }
        System.out.println();
    }
}
 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//MemberTreeSetTest.java
package collection.treeset;
 
import collection.Member;
 
public class MemberTreeSetTest {
 
    public static void main(String[] args) {
 
        MemberTreeSet memberTreeSet = new MemberTreeSet();
        
        Member memberLee = new Member(1001"이지원");
        Member memberSon = new Member(1002"손민국");
        Member memberPark = new Member(1003"박서훤");
        
        memberTreeSet.addMember(memberLee);
        memberTreeSet.addMember(memberSon);
        memberTreeSet.addMember(memberPark);
        memberTreeSet.showAllMember();
        
        Member memberHong = new Member(1003"홍길동");
        memberTreeSet.addMember(memberHong);
        memberTreeSet.showAllMember();
    }
 
}
 
cs

이렇게 했더니 Member 클래스에 Comparable 인터페이스가 구현되지 않았다는 에러가 뜸 -> Comparable 인터페이스 구현해 주어야 한다,,,,,,,,ㅎ (언제 끝나,,,12장,,,,,,,,,,,,,,,,,,,,,,,,,,,쁘엥)

Comparable 인터페이스와 Comparator 인터페이스

  • 자기 자신과 전달받은 매개변수를 비교하는 Comparable 인터페이스
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Member.java -> 회원의 아이디와 이름을 가져옴
package collection;
 
public class Member implements Comparable<Member> { //Comparable 인터페이스에는 compareTo라는 추상 메서드가 포함.
    private int memberId;
    private String memberName;
 
    public Member(int memberId, String memberName) {
        this.memberId = memberId;
        this.memberName = memberName;
    }
 
   ...
    
    @Override
    public int compareTo(Member member) {
        return (this.memberId - member.memberId);
    }
}
 
cs

새로 추가된 회원의 아이디 즉, this의 아이디와 기존 회원의 아이디를 비교한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//MemberTreeSetTest.java
package collection.treeset;
 
import collection.Member;
 
public class MemberTreeSetTest {
 
    public static void main(String[] args) {
 
        MemberTreeSet memberTreeSet = new MemberTreeSet();
        
        Member memberLee = new Member(1001"이지원");
        Member memberSon = new Member(1002"손민국");
        Member memberPark = new Member(1003"박서훤");
        
        memberTreeSet.addMember(memberLee);
        memberTreeSet.addMember(memberSon);
        memberTreeSet.addMember(memberPark);
        memberTreeSet.showAllMember();
        
        Member memberHong = new Member(1003"홍길동");
        memberTreeSet.addMember(memberHong);
        memberTreeSet.showAllMember();
        /*
        이지원 회원님의 아이디는 1001입니다.
        손민국 회원님의 아이디는 1002입니다.
        박서훤 회원님의 아이디는 1003입니다.
         */
    }
 
}
 
cs

아이디 순으로 출력된 것을 확인할 수 있다. 아이디 값을 내림차순으로 출력하기 위해서는 다음과 같이 코드를 수정하면 된다.

 @Override
    public int compareTo(Member member) {
    	return (this.memberId - member.memberId) * (-1);
    }


  • 두 매개변수를 비교하는 Comparator 인터페이스

Comparator 역시 정렬을 구현하는 데 사용하는 인터페이스이다. Comparator 인터페이스는 compare() 메서드를 구현해야 된다. 그래서 지금까지 백준을 풀었을 때, compareTo()와 compare() 2개가 있던 이유는 각 메서드를 구현하기 위한 인터페이스 차이 때문이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Member.java -> 회원의 아이디와 이름을 가져옴
package collection;
 
public class Member implements Comparator<Member> {
    private int memberId;
    private String memberName;
 
    ...
    
    @Override
    public int compare(Member mem1, Member mem2) {
        return (mem1.getMemberId() - mem2.getMemberId());
    }
}
 
cs

두 매개 변수를 비교함,,

태그:

카테고리:

업데이트:

댓글남기기