SHUSTORY

12-4 Set 인터페이스 본문

프로그래밍/JAVA

12-4 Set 인터페이스

어서오시우 2023. 3. 8. 09:51
728x90

Set 인터페이스

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

Set 인터페이스를 구현한 대표 클래스에는 HashSet, TreeSet이 있다.

 

HashSet 클래스

HashSet 클래스는 집합 자료 구조를 구현하며 중복을 허용하지 않는다.

 

예제01_HashSet 테스트하기

 

예제01에서 볼 수 있듯이 hashSet에 동일한 자료가 추가되지 않는다.

또한 ArrayList는 순서가 있는 자료 구조이기 때문에 추가한 순서대로 출력되지만,

HashSet은 자료가 추가된 순서와 상관 없이 출력된다.

 

예제02_HashSet 활용하기

 

회원을 삭제할 때 ArrayList에서는 get(i) 메서드를 사용해 i번째에 해당하는 항목을 삭제한 반면,

HashSet에서는 해당하는 아이디를 가진 회원을 찾기 위해 Iterator를 사용한다.

메서드 설명
boolean remove(Object o) 매개변수로 받은 객체를 삭제하고 삭제 여부를 true, false로
반환한다.

MemberHashSet을 생성하여 회원 집합을 추가하고, 기존에 추가된 회원과 아이디가 같은 회원을 추가하며 MemberHashSet 클래스가 잘 구현되었는지 테스트 프로그램을 실행하여 확인해보자.

 

예제03_HashSet 테스트 클래스

 

예제01에서 String("임정순")이 두 번 추가 되지 않은 이유는 String 클래스에 객체가 동일한 경우에 대한 처리 방법이 이미 구현되어 있기 때문이다.

그렇다면 Member 클래스에도 같은 아이디를 가진 회원을 같은 객체로 보고 이 경우 처리하는 방법을 구현해보자.

 

객체가 동일함을 구현하기

기본적으로 인스턴스 주소가 같으면 같은 객체이다.

예제03에서 회원 아이디가 같으면 같은 회원으로 취급하도록 예제04를 구현해보자.

Object 클래스에서 논리적으로 같은 객체를 구현하기 위해 equals( ) 메서드와 hashCode( ) 메서드를 재정의했다.

Member 클래스에도 equals( ) 메서드와 hashCode( ) 메서드를 재정의하여 회원 아이디가 같으면 같은 회원임을 구현하자.

 

예제04

 

예제04에서 hashCode( ) 메서드가 회원 아이디를 반환하도록 재정의하고,

equals( ) 메서드에서 매개변수로 받은 회원 아이디가 자신의 회원 아이디와 같다면 true 값을 반환하도록 재정의하였다.

 

예제05_예제04 재정의 후 다시 테스트 결과값 출력

재정의한 결과 회원 아이디가 같으면 같은 회원으로 간주하여 17행에서 같은 회원 아이디를 가진 회원을 추가하였을 때

추가되지 않은 결과값을 확인할 수 있다.

 

TreeSet 클래스

자바의 Collection 인터페이스나 Map 인터페이스를 구현한 클래스 중 Tree로 시작하는 클래스는 데이터를 추가한 후

결과를 출력하면 결과 값이 정렬된다.

TreeSet는 자료의 중복을 허용하지 않으면서 출력 결과 값을 정렬하는 클래스이다.

 

예제06_TreeSet 테스트

 

결과 값의 정렬 기준은 어떻게 이루어지는 것일까?

자바는 정렬을 구현하기 위해 '이진 트리'를 사용한다.

 

이진 검색 트리

트리는 자료 사이의 계층 구조를 나타내는 자료 구조이다.

부모-자식 노드

트리 자료 구조에서 각 자료가 들어가는 공간을 노드라고 하며, 위아래로 연결된 노드의 관계를 부모-자식 노드라고 한다.

이진 검색 트리는 노드에 저장되는 자료의 중복을 허용하지 않고, 부모가 가지는 자식 노드의 수는 2개 이하이다.

왼쪽 자식 노드는 부모 노드보다 항상 큰 값을 가지며, 오른쪽 자식 노드는 부모 노드보다 항상 작은 값을 가진다.

 

이진 검색 트리를 맨 왼쪽 노드부터 시작해서 왼쪽 -> 부모 -> 오른쪽 순으로 순회하면 오름차순이 된다.

반대로 오른쪽 -> 부모 -> 왼쪽 순으로 순회하면 내림차순이 된다.

자바의 TreeSet는 이진 검색 트리를 활용하여 자료를 정렬한다.

어떤 기준으로 값의 크기를 비교할 것인지는 프로그래머가 직접 구현해야 한다.

 

 

TreeSet를 활용해 회원 관리 프로그램 구현하기

예제06_TreesetTest 예제에서 별도의 코드를 구현하지 않아도 요소들이 정렬되었던 이유는 String 클래스 안에

정렬 방식이 이미 구현되어 있기 때문이다.

TreeSet를 활용하여 회원 정렬 기준을 회원 아이디순으로 하여 코드를 구현해보자.

 

예제07_TreeSet 활용

 

이제 TreeSet를 테스트하여 회원 아이디 순서대로 정렬이 되는지 확인해보자.

 

예제08_예제07 테스트

 

그런데 예제08을 보면 오류가 발생한 것을 확인할 수 있다.

오류 내용을 살펴보면 Member 클래스가 Comparable 인터페이스를 구현하지 않았다고 작성되어 있다.

즉 우리가 만든 Member 클래스를 TreeSet의 요소로 추가할 때 어떤 기준으로 노드를 비교하여 트리를 형성해야

하는지 구현하지 않았기 때문에 오류가 발생한 것이다.

회원을 TreeSet에 추가할 때 어떤 기준으로 비교할 것인지 구현해주어야 하는데,

이때 사용하는 인터페이스가 Comparable 또는 Comparator 이다.

 

자기 자신과 전달받은 매개변수를 비교하는 Comparable 인터페이스

Comparable과 Comparator는 정렬을 구현할 수 있게 해주는 인터페이스이다.

먼저 Comparable 인터페이스를 활용하여 구현해보자.

 

Comparable 인터페이스에는 CompareTo( ) 추상 메서드가 포함되어 있다.

따라서 이 인터페이스를 구현하는 Member 클래스에서 compareTo( ) 메서드를 구현해야 한다.

 

예제09_Member 클래스 수정
예제10_예제09 테스트

 

그 결과 위와 같이 아이디가 오름차순으로 정렬되어 있음을 확인할 수 있다.

만약 내림차순으로 정렬하고자 한다면 compareTo( ) 메서드 내부의 return 값을 (this.memberId - member.memberId) * (-1)로 수정하면 된다.

 

예제09에서 정의한 compareTo( ) 메서드에서 비교 대상은 새로 추가한 회원 아이디와 compareTo( ) 메서드의 매개변수로 전달된 회원 아이디이다. 두 값을 비교하여 새로 추가한 회원 아이디가 더 크면 양수, 그렇지 않으면 음수, 같으면 0이 반환되고, 이전에 설명한 이진트리 방식으로 값이 순차적으로 정렬된다.

CompareTo( )는 프로그래머가 호출하는 메서드가 아닌 객체가 TreeSet에 요소를 추가할 때 호출되는 메서드이다.

 

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

Comparator 역시 정렬을 구현하는 데 사용하는 인터페이스이다.

Comparator 인터페이스는 compare( ) 메서드를 구현해야 하는데, 이 메서드는 매개변수가 두 개 전달되며

전달된 두 매개변수를 비교한다. 첫 번째 매개변수가 더 클 때 양수를 반환하여 오름차순으로 정렬된다.

 

예제11_Comparator 인터페이스 구현 ( Member2 클래스 )

 

Comparator를 사용할 때 유의할 점은 TreeSet 생성자에 Comparator를 구현한 객체를 매개 변수로 전달한다는 것이다.

Comparator 사용 시 코드 구현 유의사항

 

일반적으로 Comparator 인터페이스보다 Comparable 인터페이스를 더 많이 사용한다.

다만 어떤 클래스가 이미 Comparable 인터페이스를 구현한 경우 이 클래스의 정렬 방식을 정의할 때 Comparator 인터페이스를 사용할 수 있다.

예를 들어 String 클래스가 Comparable 인터페이스를 이미 구현했으며, compareTo( ) 메서드는 오름차순 정렬을 구현하고 있다고 할 때, 만약 정렬 방식을 내림차순으로 바꾸고 싶을 경우 String 클래스는 final로 선언되어 있어서 상속받아 compareTo( ) 메서드를 재정의할 수도 없다. 이러한 경우 Comparator를 사용한다.

 

예제12_Comparator 인터페이스 사용

 

만약 16행에서 TreeSet 클래스를 생성할 때 생성자에 매개변수를 넣지 않으면 원래 String 클래스에 정의된 Comparable 인터페이스의 compareTo( ) 메서드 구현 내용대로 오름차순으로 정렬된다.

'프로그래밍 > JAVA' 카테고리의 다른 글

13-1 내부 클래스  (0) 2023.03.13
12-5 Map 인터페이스  (0) 2023.03.08
12-3 List 인터페이스  (0) 2023.03.08
12-2 컬렉션 프레임워크  (0) 2023.03.08
12-1 제네릭  (0) 2023.03.07