Java Map이 컬렉션을 확장하지 않는 이유
라는 사실에 놀랐다.Map<?,?>
a가 아니다.Collection<?>
.
나는 그것이 그렇게 선언된다면 많은 의미가 있을 것이라고 생각했다.
public interface Map<K,V> extends Collection<Map.Entry<K,V>>
결국 aMap<K,V>
의 수집품이지 않은가?
그래서 그렇게 시행되지 않는 이유가 있을까?
클레투스에게 가장 권위 있는 대답을 해줘서 고맙지만, 나는 아직도 왜 그런지 궁금하다, 만약 당신이 이미 a를 볼 수 있다면.Map<K,V>
로서Set<Map.Entries<K,V>>
( 경유)entrySet()
(), 대신 인터페이스만 확장하는 것이 아니다.
만약
Map
a이다Collection
, 요소들은 무엇인가?유일한 합리적인 대답은 "키-값 쌍"이다.
바로 그거야interface Map<K,V> extends Set<Map.Entry<K,V>>
정말 좋을 거야!
그러나 이는 매우 제한적(특별히 유용하지는 않음)을 제공한다.
Map
추상화
하지만 만약 그렇다면 왜 그럴까?entrySet
인터페이스에 의해 지정되었는가?어떻게든 유용할 것이다(그리고 나는 그 입장을 주장하기 쉽다고 생각한다!).
주어진 키 맵이 어떤 값에 매핑되는지 물어볼 수도 없고, 어떤 값에 매핑되는지 모르는 상태에서 해당 키의 항목을 삭제할 수도 없다.
내 말은 그게 다가 아니라는 거야.Map
! 그것은 다른 모든 방법을 유지할 수 있고 유지해야 한다.entrySet
, 그것은 지금 중복이다)!
Java Collections API Design FAQ:
맵이 수집을 확장하지 않는 이유
이건 계획적인 거였어.우리는 매핑이 집합이 아니고 집합이 매핑이 아니라고 느낀다.따라서 Map이 Collection 인터페이스(또는 그 반대)를 확장하는 것은 이치에 맞지 않는다.
지도가 집합인 경우 요소란?유일한 합리적인 답은 "키-값 쌍"이지만, 이것은 매우 제한적이고 특별히 유용하지 않은 지도 추상화를 제공한다.주어진 키 맵이 어떤 값에 매핑되는지 물어볼 수도 없고, 어떤 값에 매핑되는지 모르는 상태에서 해당 키의 항목을 삭제할 수도 없다.
맵을 확장하기 위해 컬렉션을 만들 수 있지만, 이에 따라 키가 무엇인가?라는 의문이 제기된다.정말 만족스러운 대답은 없고, 억지로 사람을 억지로 끌어내는 것은 부자연스러운 인터페이스로 이어진다.
지도는 집합(키, 값 또는 쌍의 집합)으로 볼 수 있으며, 이러한 사실은 지도(keySet, entrySet, value)의 세 가지 "수집 보기 작업"에 반영된다.원칙적으로 리스트를 요소에 대한 지도 매핑 지수로 볼 수 있지만, 이것은 리스트에서 요소를 삭제하면 삭제된 요소 이전의 모든 요소와 연관된 키가 변경되는 불쾌한 속성을 가지고 있다.그래서 리스트에 지도 보기 작업이 없는 겁니다.
업데이트: 나는 인용문이 대부분의 질문에 답한다고 생각한다.출품작의 집합이 특별히 유용한 추상화가 아니라는 점을 강조할 가치가 있다.예를 들면 다음과 같다.
Set<Map.Entry<String,String>>
다음을 허용한다.
set.add(entry("hello", "world"));
set.add(entry("hello", "world 2"));
(이른바 anentry()
a를 생성하는 방법Map.Entry
인스턴스)
Map
s는 이를 위반할 수 있도록 고유한 키를 요구한다.또는 고유한 키를Set
출품작 중에서, 그것은 사실 그렇지 않다.Set
대체적으로A이다.Set
한층 더 제한하여
논쟁의 여지없이 당신은 그 말을 할 수 있다.equals()
/hashCode()
에 대한 관계.Map.Entry
순전히 열쇠를 쥐고 있었지만 그것조차도 문제가 있다.더 중요한 것은, 그것이 정말로 어떤 가치를 더하고 있는가?당신은 일단 당신이 코너 케이스를 보기 시작하면 이 추상화가 무너지는 것을 발견할지도 모른다.
주목할 필요가 있다.HashSet
실제로 구현되는 것은HashMap
다른 길이 아니다.이것은 순전히 실행 세부사항이지만 그럼에도 불구하고 흥미롭다.
의 주된 이유.entrySet()
존재한다는 것은 키를 가로지른 다음 키를 조회할 필요가 없도록 통과를 단순화하는 것이다....라는 것을 명백한 증거로 받아들이지 마라.Map
~이어야 한다Set
출품작(임호) 중에서.
질문을 상당히 직접적으로 다루는 여러 해답을 얻었지만, 조금 뒤로 물러서서 질문을 좀 더 전반적으로 보는 것이 유용할 것 같다.즉, 자바 도서관이 어떻게 작성되는지를 구체적으로 보지 않고, 왜 그렇게 작성되는지를 살펴보는 것이다.
여기서 문제는 상속이 단지 하나의 공통성만을 본떠 만든다는 것이다.둘 다 '집합 비슷한' 것처럼 보이는 두 가지를 꼽으면 아마도 공통점이 있는 8~10가지를 꼽을 수 있을 것이다.만약 여러분이 다른 한 쌍의 "집합 비슷한" 것들을 고른다면, 그것들은 또한 8에서 10가지 공통점이 될 겁니다. 하지만 그것들은 첫 번째 한 쌍과 같은 8에서 10가지 공통점이 될 수 없을 겁니다.
십여 가지나 다른 "집합 비슷한" 것들을 보면, 사실상 모든 것들은 적어도 한 가지 다른 것들과 공통적으로 8 내지 10가지 정도의 특징을 가지고 있을 것이다. 하지만 그것들 하나하나가 공유되는 것을 보면, 사실상 아무것도 남기지 않는 것이다.
이것은 상속(특히 단일 상속)이 단지 잘 모델화되지 않는 상황이다.어떤 것이 진짜 수집품인지 아닌지는 명확한 구분선은 없지만, 의미 있는 수집 클래스를 정의하고 싶다면, 그 중 몇 개는 빼놓아야 한다.이들 중 몇 개만 제외할 경우 수집 클래스는 매우 드문 인터페이스만 제공할 수 있다.더 빼놓으면 좀 더 풍부한 인터페이스를 줄 수 있을 것이다.
어떤 이들은 또한 기본적으로 "이 유형의 수집은 운영 X를 지원하지만 X를 정의하는 기본 클래스에서 파생되어 사용할 수 없지만 파생 클래스의 X를 사용하려고 하면 실패한다(예: 예외를 발생시킴).
그것은 여전히 한가지 문제를 남긴다: 어느 것을 빼먹었든, 어느 것을 넣었든 간에, 여러분은 어떤 수업과 어떤 수업 사이에 어떤 수업인지, 어떤 수업인지에 대해 엄격한 선을 그어야만 할 것이다.그 선을 어느 곳에 그어도 꽤 비슷한 어떤 것 사이에 분명하고 다소 인위적인 분열이 남게 될 것이다.
왜 그런지 주관적인 것 같아.
C#에서, 나는 생각한다.Dictionary
컬렉션을 확장하거나 최소한 구현:
public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>,
ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>,
IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback
파로 스몰탁에서도:
Collection subclass: #Set
Set subclass: #Dictionary
그러나 일부 방법으로는 비대칭성이 있다.예를 들어.collect:
연결(입력 항목과 동일)을 수행하는 동안do:
값을 매기다그들은 다른 방법을 제공한다.keysAndValuesDo:
사전을 조목조목 반복하다 Add:
협회는 필요하지만remove:
"유효한" 상태:
remove: anObject
self shouldNotImplement
그래서 그것은 분명히 할 수 있지만, 계급 계층 구조와 관련된 다른 문제들로 이어진다.
더 좋은 것은 주관적이다.
클리투스의 대답은 좋지만 의미론적 접근법을 추가하고 싶다.두 가지를 모두 결합하는 것은 말이 되지 않기 때문에, 수집 인터페이스를 통해 키-값-페어를 추가하는 경우를 생각해 보십시오.지도 인터페이스는 키와 관련된 하나의 값만 허용한다.그러나 동일한 키로 기존 항목을 자동으로 제거하면 컬렉션은 이전과 동일한 크기를 추가한 후 컬렉션에 대해 매우 예상치 못한 크기를 갖게 된다.
자바 컬렉션이 망가졌다.관계 인터페이스가 누락되어 있다.따라서, 지도가 관계를 확장하면 집합이 확장된다.관계(멀티맵이라고도 함)는 고유한 이름-값 쌍을 가지고 있다.지도("기능"이라고 함)는 물론 가치에 매핑되는 고유한 이름(또는 키)을 가지고 있다.시퀀스는 맵을 확장한다(각 키가 0보다 큰 정수임).가방(또는 멀티셋)은 맵을 확장한다(각 키는 요소이고 각 값은 백에 요소가 나타나는 횟수임).
이 구조물은 다양한 "집합" 범위의 교차점, 결합 등을 허용한다.따라서 계층 구조는 다음과 같아야 한다.
Set
|
Relation
|
Map
/ \
Bag Sequence
Sun/Orace/Java ppl - 다음 번에는 바로 가져오십시오.고마워요.
Map<K,V>
연장해서는 안 된다Set<Map.Entry<K,V>>
이후:
- 다른 것을 추가할 수는 없다.
Map.Entry
s 동일한 키를 가진Map
그렇지만 - 다른 항목을 추가할 수 있음
Map.Entry
s 동일한 키를 가진Set<Map.Entry>
.
각각의 데이터 구조를 보면 그 이유를 쉽게 짐작할 수 있다.Map
의 일부가 아니다Collection
각각Collection
단일 값을 에 저장하다.Map
키 값 쌍 저장그래서 메소드는Collection
인터페이스가 에 호환되지 않음Map
접점예를 들어Collection
우리는 가지고 있다.add(Object o)
. 이러한 구현은 무엇에 해당될 것인가?Map
. 그런 방법을 가지고 있다는 것은 말이 안 된다.Map
대신 우리는put(key,value)
에 있어서의 방법.Map
.
같은 논거가 있다.addAll()
remove()
그리고removeAll()
방법들그래서 가장 큰 이유는 데이터가 저장되는 방식의 차이 때문이다.Map
그리고Collection
. 또한 당신이 기억한다면.Collection
인터페이스 구현Iterable
인터페이스(즉, 모든 인터페이스와.iterator()
메소드는 에 저장된 값을 반복할 수 있는 반복기를 반환해야 한다.Collection
이제 그러한 방법은 무엇에 대한 보상을 할 것인가?Map
키 핵심 반복기 또는 가치 반복기?이것도 말이 안 된다.
우리가 키와 가치관을 반복할 수 있는 방법이 있다.Map
그리고 그것이 그것의 일부분이다.Collection
골격
바로 그거야
interface Map<K,V> extends Set<Map.Entry<K,V>>
정말 좋을 거야!
사실 그랬다면implements Map<K,V>, Set<Map.Entry<K,V>>
그럼 난 동의하는 편해그것은 심지어 자연스러워 보인다.그런데 그게 잘 안 되잖아?가지고 있다고 가정해 보자.HashMap implements Map<K,V>, Set<Map.Entry<K,V>
LinkedHashMap implements Map<K,V>, Set<Map.Entry<K,V>
다가 ...을... 그건 다 좋은데, 만약 네가 그랬다면.entrySet()
, 아무도 그 방법의 구현을 잊지 않을 것이고, 당신은 어떤 지도에 대해서도 entrySet를 얻을 수 있다는 것을 확신할 수 있지만, 만약 당신이 구현자가 두 가지 인터페이스를 모두 구현하기를 원한다면...
내가 갖고 싶지 않은 이유interface Map<K,V> extends Set<Map.Entry<K,V>>
단순히, 더 많은 방법이 있을 것이기 때문이다.그리고 결국, 그것들은 다른 것들이야, 그렇지?또 아주 현실적으로, 만약 내가 때린다면map.
IDE에서는 보고 싶지 않다..remove(Object obj)
그리고.remove(Map.Entry<K,V> entry)
할 수 없기 때문에hit ctrl+space, r, return
그리고 끝장을 내라.
솔직하고 심플하다.집합은 하나의 개체만을 기대하는 인터페이스인 반면, 지도에는 두 개만 필요하다.
Collection(Object o);
Map<Object,Object>
참조URL: https://stackoverflow.com/questions/2651819/why-doesnt-java-map-extend-collection
'programing' 카테고리의 다른 글
Vue.js 클래스 이름으로 프로펠러 값 사용 (0) | 2022.05.04 |
---|---|
순기능의 이점 (0) | 2022.05.04 |
Apache에서 vue 기록이 있는 https 강제 적용 (0) | 2022.05.04 |
vuexfire로 쿼리하는 방법 (0) | 2022.05.04 |
내 jar File에서 리소스 폴더의 폴더에 액세스하는 방법 (0) | 2022.05.04 |