나는 Map<?,?>아닌 사실에 놀랐습니다 Collection<?>.
나는 그것이 그렇게 선언되면 많은 의미가 있다고 생각했다.
public interface Map<K,V> extends Collection<Map.Entry<K,V>>
결국,의 Map<K,V>모음입니다 Map.Entry<K,V>, 그렇지 않습니까?
그렇다면 왜 그렇게 구현되지 않은 좋은 이유가 있습니까?
가장 권위있는 답변 클리 터스 덕분에,하지만, 난 여전히 왜, 당신은 이미를 볼 수 있는지 궁금하네요 Map<K,V>으로 Set<Map.Entries<K,V>>(통해 entrySet()), 그냥 그 대신 인터페이스를 확장하지 않습니다.
a
Map가 인 경우Collection요소는 무엇입니까? 합리적인 대답은 “키-값 쌍”입니다.
정확히, interface Map<K,V> extends Set<Map.Entry<K,V>>좋을 것입니다!
그러나 이것은 매우 제한적이고 (특히 유용하지는 않은)
Map추상화를 제공합니다.
그러나 이것이 사실이라면 왜 entrySet인터페이스에 의해 지정됩니까? 그것은 어떻게 든 유용해야합니다 (그리고 나는 그 입장에 대해 논쟁하기 쉽다고 생각합니다!).
주어진 키가 어떤 값에 매핑되는지 물어볼 수 없으며, 어떤 키에 매핑되는지를 몰라도 주어진 키에 대한 항목을 삭제할 수 없습니다.
나는 그것이 전부라고 말하는 것이 아닙니다 Map! 다른 모든 방법을 유지할 수 있고 유지 해야 합니다 ( entrySet지금은 중복됩니다 제외 )!
답변
로부터 자바 컬렉션 API 디자인 자주 묻는 질문 :
지도가 컬렉션을 확장하지 않는 이유는 무엇입니까?
이것은 의도적으로 설계된 것입니다. 우리는 매핑이 컬렉션이 아니며 컬렉션이 매핑이 아니라고 생각합니다. 따라서 Map이 Collection 인터페이스를 확장하는 것은 의미가 없습니다.
지도가 컬렉션 인 경우 요소는 무엇입니까? “키-값 쌍”이 합리적으로 정해지지 만 매우 제한적인 (특히 유용하지는 않은) 맵 추상화를 제공합니다. 주어진 키가 어떤 값에 매핑되는지 물어볼 수 없으며, 어떤 키에 매핑되는지를 몰라도 주어진 키에 대한 항목을 삭제할 수 없습니다.
Map을 확장하기 위해 컬렉션을 만들 수 있지만, 이것이 무엇입니까? 실제로 만족스러운 답변은 없으며 강제로 부 자연스러운 인터페이스를 만듭니다.
지도는 컬렉션 (키, 값 또는 쌍)으로 볼 수 있으며이 사실은지도의 세 가지 “컬렉션보기 작업”(keySet, entrySet 및 값)에 반영됩니다. 원칙적으로 List를 요소에 대한 맵 매핑 인덱스로 볼 수는 있지만 List에서 요소를 삭제하면 삭제 된 요소 이전의 모든 요소와 관련된 키가 변경되는 불쾌한 속성이 있습니다. 그렇기 때문에 목록에 대한지도보기 작업이 없습니다.
업데이트 : 견적이 대부분의 질문에 대한 답변이라고 생각합니다. 특별히 유용한 추상화가 아닌 항목 모음에 대해 강조 할 가치가 있습니다. 예를 들면 다음과 같습니다.
Set<Map.Entry<String,String>>
허용 할:
set.add(entry("hello", "world"));
set.add(entry("hello", "world 2");
( 인스턴스 entry()를 생성 하는 메소드를 가정 Map.Entry)
Map고유 한 키가 필요하므로이를 위반할 수 있습니다. 또는 Set여러 항목 에 고유 키를 적용하면 실제로 Set일반적인 의미는 아닙니다. 그것은이다 Set더 제한.
논란의 여지가 있지만 equals()/ hashCode()관계 Map.Entry는 순전히 핵심이지만 문제가 있습니다. 더 중요한 것은 실제로 가치를 더 하는가? 코너 케이스를 살펴보기 시작하면이 추상화가 손상 될 수 있습니다.
HashSet는 실제로 HashMap다른 방법으로 구현 되지 않고 로 구현 된다는 점에 주목할 가치가 있습니다. 이것은 순전히 구현 세부 사항이지만 그럼에도 불구하고 흥미 롭습니다.
entrySet()존재 하는 주된 이유 는 순회를 단순화하여 키를 순회 한 다음 키를 조회 할 필요가 없기 때문입니다. Mapa Set가 항목 (imho) 이어야한다는 원시적 증거로 간주하지 마십시오 .
답변
귀하의 질문을 상당히 직접적으로 다루는 많은 답변을 얻었지만 조금 뒤로 물러나서 더 일반적으로 질문을 보는 것이 도움이 될 것입니다. 즉, Java 라이브러리가 어떻게 작성되는지 구체적으로 보지 말고 왜 그렇게 작성했는지 살펴보십시오.
여기서 문제는 상속은 한 가지 유형의 공통성을 모델링한다는 것 입니다. 둘 다 “컬렉션과 같은”것으로 보이는 두 가지를 골라낸다면 아마도 공통점이있는 8 개 또는 10 개를 선택할 수 있습니다. 다른 “컬렉션과 같은”항목을 선택하면 공통적으로 8 개 또는 10 개의 항목이 있지만 첫 번째 항목과 같은 8 개 또는 10 개 는 아닙니다 .
당신이 다스 또는 그렇게 다를 경우 “컬렉션 같은”것들, 거의 그들 모두는 아마 적어도 하나의 다른 하나의 공통점이 8 개 또는 10 특성 같은 것을해야합니다 -하지만 당신이 보면에서 공유 있는지 마다 하나 그들 중 거의 아무것도 남지 않았습니다.
이것은 상속 (특히 단일 상속)이 잘 모델링되지 않는 상황입니다. 어떤 컬렉션이 실제로 컬렉션인지 아닌지에 대한 명확한 구분선은 없지만 의미있는 Collection 클래스를 정의하려는 경우 일부를 생략해야합니다. 그중 몇 개만 남겨두면 Collection 클래스는 아주 드문 인터페이스 만 제공 할 수 있습니다. 더 많이 나가면 더 풍부한 인터페이스를 제공 할 수 있습니다.
일부는 또한 기본적으로 다음과 같은 옵션을 취합니다. “이 유형의 컬렉션은 작업 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
Pharo Smalltak에서도 :
Collection subclass: #Set
Set subclass: #Dictionary
그러나 일부 방법에는 비대칭 성이 있습니다. 예를 들어, 값 collect:을 do:가져 오는 동안 연결 (항목과 동등한 항목)을 사용합니다. keysAndValuesDo:항목별로 사전을 반복 하는 다른 방법 을 제공합니다 . Add:연결을 취하지 만 remove:“억제”되었습니다.
remove: anObject
self shouldNotImplement
따라서 결정적으로 가능하지만 클래스 계층 구조와 관련된 다른 문제가 발생합니다.
더 나은 것은 주관적입니다.
답변
cletus의 대답은 좋지만 의미 론적 접근법을 추가하고 싶습니다. 두 가지를 결합하는 것은 의미가 없으며 수집 인터페이스를 통해 키-값 쌍을 추가하고 키가 이미 존재하는 경우를 생각해보십시오. 맵 인터페이스는 키와 관련된 하나의 값만 허용합니다. 그러나 동일한 키를 사용하여 기존 항목을 자동으로 제거하면 컬렉션은 이전과 동일한 크기를 추가 한 후에 컬렉션에 대해 예상치 못한 결과를 가져옵니다.
답변
Java 콜렉션이 손상되었습니다. 인터페이스의 인터페이스가 누락되었습니다. 따라서 맵은 관계 확장 세트를 확장합니다. 관계 (멀티 맵이라고도 함)에는 고유 한 이름-값 쌍이 있습니다. 맵 (일명 “함수”)에는 고유 한 이름 (또는 키)이 있으며 물론 값에 매핑됩니다. 시퀀스는 맵을 확장합니다 (각 키는 정수> 0). 가방 (또는 다중 세트)은 맵을 확장합니다 (여기서 각 키는 요소이고 각 값은 요소가 가방에 나타나는 횟수).
이 구조는 다양한 “컬렉션”의 교차점, 결합 등을 허용합니다. 따라서 계층 구조는 다음과 같아야합니다.
Set
|
Relation
|
Map
/ \
Bag Sequence
Sun / Oracle / Java ppl-다음에 바로 받아보십시오. 감사.
답변
각 데이터 구조를 보면 왜 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입니다.
