현재 위치 - 인적 자원 플랫폼망 - 미니프로그램 자료 - 집합의 간단한 분석
집합의 간단한 분석
집합의 주요 특징은 다음과 같습니다: 요소는 중복되지 않고, 저장소는 정렬되지 않습니다.

열쇠 집합의 주요 구현 클래스는 HashSet, LinkedHashSet, TreeSet, EnumSet (RegularEnumSet, JumboEnumSet) 등입니다.

그림의 상속 관계에서 Set 인터페이스의 주요 구현 클래스는 AbstractSet, HashSet, LinkedHashSet, TreeSet, EnumSet( RegularEnumSet, JumboEnumSet )가 있으며, 이 중 AbstractSet과 EnumSet은 추상 클래스에 속하고, EnumSet은 jdk1.5에 새로 추가되었으며, 차이점은 EnumSet 컬렉션 요소는 열거형이어야 한다는 것입니다.

HashSet은 입력과 출력의 정렬되지 않은 컬렉션입니다. 집합의 요소는 HashMap의 키 구현을 기반으로 하며 요소는 중복될 수 없습니다.

LinkedHashSet은 입력-출력 정렬 컬렉션으로, 컬렉션의 요소는 LinkedHashMap의 키 구현을 기반으로 하며 요소는 반복될 수 없습니다.

TreeSet은 정렬된 집합이고, 집합의 요소는 TreeMap의 키 구현을 기반으로 하며, 동일한 요소는 반복될 수 없습니다.

EnumSet은 열거형에 사용되는 특수 집합으로, RegularEnumSet과 JumboEnumSet은 개별적으로 인스턴스화할 수 없고 오직 EnumSet 생성으로만 생성할 수 있으며, 동일한 요소를 반복할 수 없습니다.

주요 구현 클래스를 하나씩 분석해 보겠습니다!

HashSet은 입력과 출력의 정렬되지 않은 컬렉션으로, 기본 구현은 HashMap을 기반으로 하며, 소스 코드에서 볼 수 있듯이 HashSet은 HashMap의 핵심 요소를 사용하여 요소를 저장합니다. 소스 코드를 다음과 같이 읽어보세요:

공개 클래스 HashSet & ltE & gt

확장 클래스 AbstractSet & ltE & gt

도구 집합 & ltE & gt, Cloneable, java.io.Serializable{

}

오픈 다음 소스 코드가 있는 HashSet의 add() 메서드:

공개 부울 add(E e) {

// 해시맵에 요소를 추가합니다

return map.put(e, PRESENT) = = null;

}

여기에서 변수 PRESENT가 null이 아닌 객체인 경우, 소스 코드는 다음과 같습니다:

비공개 정적 최종 객체 PRESENT = new Object();

추가() 시 다음과 같다고 분석할 수 있습니다

HashMap map = new HashMap & lt& gt();

map.put(e, new Object( )); //e는 추가할 요소를 나타냅니다.

이전 컬렉션 기사에서 HashMap이 요소를 추가할 때 equals() 및 hashCode() 메서드를 사용하여 들어오는 키가 동일한지 확인하는 방법을 배웠습니다. 키가 같으면 해시맵은 추가된 요소를 동일한 것으로 간주하고 그 반대의 경우도 마찬가지입니다.

소스코드 분석 결과, HashSet은 HashMap의 이 기능을 사용하여 무질서한 첨자가 있는 요소를 저장하는 특성을 달성하고 요소가 반복되지 않는다는 것을 알 수 있습니다.

HashSet의 remove 메서드 역시 HashMap의 기본 구현을 기반으로 하며, 소스 코드는 다음과 같습니다.

public boolean remove(object o) {

// HashMap의 remove 메서드를 호출하여 요소를 제거합니다.

return map . remove(o) == PRESENT;

}

해시셋은 리스트나 맵과 같은 get 메서드를 제공하지 않고 대신 이터레이터나 for 루프를 사용해 요소를 반복합니다. 이러한 메서드는 다음과 같습니다.

Public static void main(String[] args) {

Set & lt string & gthashSet = new HashSet & lt string & gt();

System.out.println("HashSet 초기 용량 크기:. "+HashSet . size());

해시셋 . add(" 1 ");

해시셋 . add(" 2 ");

해시셋 . ADD(" 3 ");

HASHSET . ADD(" 3 ");

HASHSET . ADD(" 2 ");

HASHSET . add(null);

}

출력:

해시셋 초기 용량 크기:0

해시셋 용량 크기:4

null, 1, 2, 3,

===========

null, 1, 2, 3,

주의해야 할 사항은 다음과 같습니다. 는 null 요소를 추가할 수 있다는 점입니다.

LinkedHashSet은 입력과 출력의 정렬된 컬렉션으로, HashSet에서 상속되었지만 기본 구현은 LinkedHashMap을 기반으로 합니다.

링크드해시맵을 이미 알고 계셨다면, 이 역시 해시맵에서 상속된다는 것을 알고 계실 것입니다. 유일한 차이점은 LinkedHashMap의 기본 데이터 구조가 순환 연결 목록을 기반으로 하며 배열이 머리와 꼬리를 지정한다는 점입니다. 배열의 첨자는 정렬되지 않은 방식으로 저장되지만, 요소를 저장하는 과정은 배열의 머리와 꼬리, 순환 연결 목록을 통해 순차적으로 쿼리할 수 있으므로 입력과 출력이 정렬되는 특성을 갖습니다.

링크드해시맵의 구현 과정을 잘 모르신다면 링크드해시맵의 구현 과정에 대한 글 모음 시리즈를 참고하시면 됩니다.

LinkedHashSet의 소스 코드를 읽어보면, 클래스 정의는 다음과 같습니다:

공개 클래스 LinkedHashSet & ltE & gt

Extended HashSet & ltE & gt

Toolset & ltE & gt, Cloneable, java.io. Serializable {

}

소스 코드를 쿼리하고 메서드를 슈퍼 호출하면 소스 코드는 다음과 같습니다:

HashSet(int initialCapacity, float loadFactor, boolean dummy) {

//initialise the LinkedHashMap.

map = new LinkedHashMap & lt& gt(initialCapacity, loadFactor);

}

LinkedHshSet은 add 메서드를 오버라이드하는 대신 HashSet의 add() 메서드를 직접 호출합니다. 지도의 구현 클래스는 LinkedHashMap이므로 여기서는 LinkedHashMap에 요소를 추가하고 있습니다. add() 함수는 다음과 같습니다

HashMap map = new linked HashMap & lt; & gt();

map.put(e, new Object()); //e는 추가할 요소를 나타냅니다.

LinkedHashSet은 제거 메서드를 오버라이드하지 않고 HashSet의 삭제 메서드를 직접 호출합니다. LinkedHashMap은 제거 메서드를 재정의하지 않기 때문에 HashMap의 제거 메서드도 호출합니다. 소스 코드는 다음과 같습니다:

public boolean remove(object o) {

// HashMap의 remove 메서드를 호출하여 요소를 제거합니다.

return map . remove(o) == PRESENT;

}

유사하게, LinkedHashSet은 다음과 같이 get 메서드를 제공하지 않고 대신 이터레이터 또는 for 루프를 사용하여 요소를 반복합니다:

public static void main(String[] args) {

set & lt. String & gtlinked hashset = new linked hashset & lt; String & gt();

System. out.println ("Linked hashset 초기 용량 크기:"+Linked hashset . size());

linkedhashset . add(" 1 ");

linkedhashset . add(" 2 ");

linkedhashset . ADD(" 3 ");

LINKEDHASHSET . ADD(" 3 ");

LINKEDHASHSET . add(" 2 ");

LINKEDHASHSET . add(null);

LINKEDHASHSET . add(null);

}

Output:

LinkedHashSet의 초기 용량 크기:0

LinkedHashSet의 용량 크기:4

1, 2, 3, null,

===========

1, 2, 3. Empty,

링크드해시셋의 입력과 출력이 해시셋에 비해 정렬되어 있음을 알 수 있습니다.

TreeSet은 탐색 가능한 집합, 정렬된 집합, 집합 인터페이스를 구현하는 정렬된 집합으로, 기본은 TreeMap 구현에 기반하고 있습니다. TreeSet은 TreeMap의 키 요소를 사용하여 요소를 저장하며, 이는 소스 코드에서도 확인할 수 있습니다. 소스 코드를 읽어보면, 클래스 정의는 다음과 같습니다.

공개 클래스 TreeSet & ltE & gt extends AbstractSet & ltE & gt

NavigableSet & ltE & gt, Cloneable, java.io.Serializable의 구현 {

}

새 TreeSet & lt& gt() 오브젝트 구현

인스턴스화할 때 표현되는 의미는 다음과 같이 단순화할 수 있습니다.

NavigableMap & lte, Object & gtm = new TreeMap & lte, Object & gt();

TreeMap은 NavigableMap 인터페이스를 구현하므로 아무런 문제가 없습니다.

공개 클래스 TreeMap & ltk, V & gt

추상Map & ltk, V & gt 확장

내비게이블맵 & ltk, V & gt, Cloneable, java.io.Serializable 구현{

......

}

나무 집합 추가() 메서드를 열면 소스 코드는 다음과 같습니다:

공개 부울 추가(E e) {

// TreeMap에 요소를 추가

return m.put(e, PRESENT) = = null;

}

이것은 변수도 null이 아닌 객체이며, 소스 코드는 다음과 같습니다.

비공개 정적 최종 객체 PRESENT = new Object();

추가() 시 다음과 같다고 분석할 수 있습니다

TreeMap map = new TreeMap & lt& gt();

map. put(e, new Object()); //e는 추가할 요소를 나타냅니다.

TreeMap 클래스의 주요 기능은 추가된 컬렉션 요소를 새로운 규칙에 따라 정렬하는 것입니다. 기본적으로 자연스러운 순서로 정렬되지만 물론 사용자 정의할 수 있습니다. 예를 들어, 테스트 메서드는 다음과 같습니다.

public static void main(String[] args) {

map init map = new TreeMap();

initMap.put("4", " d ");

initMap.put("3", " c ")

initMap.put("1", " a ");

initMap.put("2", " b ");

// 기본 자연 정렬, 키 오름차순.

System.out.println("기본 정렬 결과:"+init map . tostring());

// 사용자 지정 정렬, 비교기 내부 객체에서 TreeMap 초기화 전달.

map comparator map = new TreeMap & lt; String, String & gt(new comparator & lt string & gt() {

@override

public int compare(String o 1, String o2){

// 키 비교의 크기에 따라 플래시백을 사용하여 가장 큰 것부터 가장 작은 것까지 정렬합니다.

리턴값은 o2 입니다. compare to(o 1);

}

});

comparatorMap.put("4", " d");

comparatorMap.put("3", " c");

comparatorMap.put("1", " a");

comparatorMap.put("2", " b");

System.out.println("사용자 지정 정렬 결과:"+comparator map . tostring());

}

출력:

기본 정렬 결과:

기본 정렬 결과:{1=a, 2=b, 3=c, 4=d}

사용자 정의 정렬 결과:{4=d, 3=c, 2=b, 1=a}

트리맵을 사용해본 사람이라면 TreeMap 이 특정 규칙에 따라 키워드를 자동으로 정렬한다는 것을 알고 있을 것입니다. TreeSet은 TreeMap의 이 기능을 사용하여 추가된 요소 집합을 구현하고 결과를 출력할 때 정렬합니다.

트리맵 구현 과정에 대한 소스코드를 보지 못했다면, 트리맵 구현 과정에 대한 컬렉션 시리즈를 참고하거나 jdk 소스코드를 읽어보시기 바랍니다.

TreeSet의 삭제 메서드도 TreeMap의 기본 구현을 기반으로 합니다. 소스 코드는 다음과 같습니다:

public boolean remove(object o) {

// TreeMap의 remove 메서드를 호출하여 요소를 제거합니다.

return m . remove(o) == PRESENT;

}

TreeSet은 get 메서드를 재정의하지 않고 대신 다음과 같이 이터레이터 또는 for 루프를 사용하여 요소를 반복합니다:

public static void main(String[] args) {

Set & lt string & . gttreeSet = new tree set & lt& gt();

System.out.println("treeSet 초기 용량 크기:"+treeSet . size());

treeset . add(" 1 ");

treeset . add(" 4 ");

treeset . add(" 3 ");

treeset . add(" 8 ");

treeset . add(" 5 ");

}

출력:

treeset 초기 용량 크기:0

treeset 용량 크기:5

1,3,4,5,8,

===========

1,3,4,5,8,

사용하는 방법에는 두 가지가 있습니다. 사용자 지정 정렬. 첫 번째 방법은 추가해야 하는 요소의 클래스에서 Comparable 인터페이스를 구현하고 compareTo 메서드를 재정의하여 사용자 지정 정렬을 위해 요소를 비교하는 것입니다.

/**

비교 가능한 인터페이스를 구현하고, compareTo 메서드를 재정의하고, 변수 나이를 통해 사용자 지정 정렬 테스트를 구현하는 Person 엔티티 클래스를 만듭니다. 메서드는 다음과 같습니다:

공개 static void main(String[] args) {

Set & ltPerson & gttreeSet = new treeSet & lt& gt();

System.out.println("treeSet 초기 용량 크기:"+. treeSet . size());

TreeSet.add(newcomer("Li1", 18));

TreeSet.add(newcomer("Li2", 17));

TreeSet.add(newcomer("Li3", 19));

TreeSet.add(newcomer("Li4" , 21));

TreeSet.add(newcomer("Wu Li", 20));

}

출력:

TreeSet 초기 용량 크기:0

TreeSet 용량 크기:5

최연소부터 최고령까지 연령별로 정렬합니다. 사용자 지정 정렬 결과:

Li 2:17, Li 1:18, Li 3:19, Wu Li:20, Li 4:21,

두 번째 방법은 TreeSet 초기화 단계에서 Comparator 인터페이스를 내부 클래스 형태의 파라미터로 초기화하여 Person이 Comparable 인터페이스를 구현할 필요가 없는 경우입니다. 메서드는 다음과 같습니다:

public static void main(String[] args) {

//custom sort

set & ltPerson & gttreeSet = new TreeSet & lt& gt(new Comparator & ltPerson & gt(){

@override

public int Compare(Person o1, Person o2) {

if(o1 == null || o2 == null){

//비교 없음

Returns 0;

}

//가장 작은 것부터 가장 큰 것까지 정렬

Returns o 1 . getage()-O2 . getage();

}

});

System.out.println("treeSet 초기 용량 크기:"+treeSet . size());

TreeSet.add(newcomer("Li1", 18));

TreeSet.add(newcomer("Li2", 17));

TreeSet.add(newcomer("Li3", 19));

TreeSet.add(newcomer("Li4" , 21));

TreeSet.add(newcomer("Wu Li", 20));

}

출력:

TreeSet 초기 용량 크기:0

TreeSet 용량 크기:5

최연소부터 최고령까지 연령별로 정렬합니다. 사용자 지정 정렬 결과:

Li2:17, Li1:18, Li3:19, WuLi:20, Li4:21,

트리 집합에 빈 요소를 추가할 수 없으며, 그렇지 않으면 널 포인터 오류가 보고됩니다!

EnumSet은 열거형에 대한 특수 컬렉션 집합으로, AbstractSet 클래스에서 상속됩니다. HashSet, LinkedHashSet 및 TreeSet과 달리 EnumSet 요소는 열거형이어야 하며 모든 요소는 동일한 열거형이어야 합니다.

공개 추상 클래스 EnumSet & lte extends EnumSet E & gt & gt extends AbstractSet. & ltE & gt

Cloneable, java.io.Serializable의 구현 {

......

}

EnumSet은 가상 클래스이므로 인스턴스화를 통해 직접 객체를 가져올 수 없습니다. EnumSet 구현 클래스에서 제공하는 정적 메서드를 통해서만 클래스의 인스턴스를 반환할 수 있습니다.

EnumSet에는 두 개의 구현 클래스, 즉 RegularEnumSet과 JumboEnumSet이 있으며, 둘 다 EnumSet에서 상속됩니다.

EnumSet은 열거형에 포함된 요소의 수에 따라 반환할 구현 클래스를 결정합니다. EnumSet 요소의 요소 수가 64보다 작거나 같으면 RegularEnumSet 인스턴스가 반환되고, EnumSet 요소의 수가 64보다 크면 JumboEnumSet 인스턴스가 반환됩니다.

소스코드에서 이를 확인할 수 있는 예는 다음과 같습니다.

Public static & lte extended enumSet E & gt& gtEnumSet & ltE & gtnone of(Class & lt; E & gtelementType) {

enumSet & lt? & gt[]universe = get universe(element type);

if (universe == null)

Throw new ClassCastException(element type+"not an enum");

// 요소 수가 64보다 작거나 같으면 RegularEnumSet.

if(universe . length & lt; = 64)

Return new RegularEnumSet & lt& gt(elementType, universe);

Other

// 64보다 크면, JumboEnumSet을 반환합니다.

Return new JumboEnumSet & lt& gt(elementType, universe);

}

NoneOf는 어떤 구현 클래스를 반환할지 결정하는 EnumSet의 정적 메서드입니다.

요소 수가 64보다 작거나 같을 때 RegularEnumSet을 사용하는 클래스를 살펴봅시다. 소스 코드는 다음과 같습니다:

class RegularEnumSet & lte 확장 열거형 E & gt& gt 확장 열거형 E & ltE & gt{

}

RegularEnumSet은 이진 연산으로 결과를 얻고, 요소를 long에 직접 저장합니다.

요소 수가 64보다 클 때 JumboEnumSet을 사용하는 클래스를 살펴봅시다. 소스 코드는 다음과 같습니다.

class JumboEnumSet & lte 확장 열거형 E & gt& gt 확장 열거형 & ltE & gt{

}

JumboEnumSet도 이진 연산으로 결과를 얻고 요소를 long에 저장하지만, 요소를 배열에 저장합니다.

이 둘을 비교하면, 연산 단계가 더 적고 대부분의 경우 REGUARENUMSET을 반환하기 때문에 REGUARENUMSET이 JumboEnumSet보다 효율적입니다. 열거 요소의 수가 64개 이상인 경우에만 JumboEnumSet이 사용됩니다.

요소 추가하기:

/// 새 EnumEntity 열거 유형을 생성하고 두 개의 매개변수를 정의합니다.

공개 열거형 열거 {

Woman, Man;

}

빈 열거형 집합 만들기:

// 빈 내용이 있는 EnumSet을 만듭니다.

EnumSet & ltEnumEntity & gtnoneSet = enum set . none of(enum entity . 클래스);

system . out . println(noneSet);

출력:

[]

열거형 집합을 생성하고 열거형 유형의 모든 요소를 추가합니다:

///열거형 집합을 생성하고 EnumEntity 요소의 내용을 EnumSet에 추가합니다.

EnumSet & ltEnumEntity & gtall set = enum set . allof(enum entity . class);

system . out . println(all set);

출력:

[Woman, Man]

열거형 집합 생성 및 지정된 열거형 요소 추가:

// 열거형 집합을 생성하고 열거형 집합에 여성을 추가합니다.

EnumSet & ltEnumEntity & gtcustomSet = 열거형 집합 . of(열거형 엔티티. 여성);

system . out . println(customSet);

요소 쿼리

해시셋, 링크드해시셋, 트리셋과 마찬가지로 EnumSet은 다음과 같이 이터레이터 또는 for 루프를 통해 요소를 순회합니다:

EnumSet & ltEnumEntity & GTALL SET = ENUM SET . allof(enum entity . class);

for(EnumEntity EnumEntity:all set){

System.out.print(enumEntity + ",");

}

Output:

Woman, Man,

해시셋은 입력과 출력이 순서가 지정되지 않고 요소가 반복되지 않는 컬렉션입니다. 기본 키 구현은 해시맵을 기반으로 하며 요소는 비어 있을 수 있습니다. 추가된 요소가 객체인 경우 객체는 동일한 요소인지 여부를 제한하기 위해 equals() 및 hashCode() 메서드를 재정의해야 합니다.

LinkedHashSet은 해시셋을 상속하는 입력-출력 정렬 컬렉션으로, 이러한 요소는 더 이상 중복되지 않습니다. 기본 키 구현은 LinkedHashMap을 기반으로 하며, 요소는 비어 있을 수도 있습니다.LinkedHashMap은 순환 링크 목록 구조를 사용하여 입력과 출력이 정렬되도록 합니다.

TreeSet은 반복할 수 없는 요소를 포함하는 정렬된 집합입니다. 기본 구현은 TreeMap의 키를 기반으로 하며 요소는 비어 있을 수 없습니다. 기본적으로 요소는 자연 순서에 따라 저장됩니다. 비교 가능 및 비교기 인터페이스를 사용하여 크기를 비교하여 사용자 지정 정렬을 수행할 수도 있습니다.

EnumSet은 열거형과 함께 사용되는 특수 컬렉션 Set으로, jdk1.5에 추가되었습니다.EnumSet은 명시적으로 인스턴스화할 수 없는 두 가지 구현 클래스인 Regularennumset과 JumboEnumSet이 있는 가상 클래스이며, EnumSet은 사용할 구현 클래스를 동적으로 결정합니다. 요소의 수가 64보다 작거나 같으면 Regularennumset이 사용되고 64보다 크면 JumboEnumSet 클래스가 사용됩니다. EnumSet은 비트 벡터로 구현되며 시간적 성능이 매우 높습니다. 요소가 열거형인 경우 EnumSet을 사용하는 것이 좋습니다.

1. JDK 1.7 & amp; JDK1.8 소스 코드

2. 프로그램 파크 - 자바 컬렉션 - EnumMap 및 EnumSet

3. 자바 긱스 테크 - /javageektech/article/. details/10307788