2011-05-12 3 views
3

다음 코드는 컴파일되지만 주석 처리 된 행의 주석 처리를 제거하면 그 이유가 혼동 스럽습니다. HashMap은 AbstractMap을 확장하고 map이 선언 된 첫 번째 라인은 잘 컴파일됩니다.Java 일반 질문

import java.util.AbstractMap; 
import java.util.HashMap; 
import java.util.Map; 

public class Test { 

    public static void main(String args[]) { 
     Map<String, ? extends AbstractMap<String, String>> map = new HashMap<String, HashMap<String, String>>(); 
     //map.put("one", new HashMap<String, String>()); 
    } 
} 

는, 나는 "올바른 방법"이 알고 :

import java.util.HashMap; 
import java.util.Map; 

public class Test { 

    public static void main(String args[]) { 
     Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>(); 
     map.put("one", new HashMap<String, String>()); 
    } 
} 

답변

7

첫 번째 코드는 안전하지 않습니다 - 당신이 실제로 작성하고 상상 : 이제

HashMap<String, ConcurrentHashMap<String, String>> strongMap = 
    new HashMap<String, ConcurrentHashMap<String, String>>(); 
Map<String, ? extends AbstractMap<String, String>> map = strongMap; 

:

map.put("one", new HashMap<String, String>()); 
ConcurrentHashMap<String, String> x = strongMap.get("one"); 

우리 에는 ConcurrentHashMap이 있지만 실제로는 HashMap 만 있습니다.

이것은 우리가 ... 시나리오가 정말 입니다 상당 (말)로가는 제네릭의 양을 줄일 경우 설명하기 위해 실제로 많은 간단합니다 : 당신이 고려해야 할 때까지, 좋아 보이는

List<? extends Fruit> list = new List<Apple>(); 
list.add(new Apple()); 

분명히 확인 하지

List<Apple> apples = new ArrayList<Apple>(); 
List<? extends Fruit> list = apples; 
list.add(new Orange()); 
Apple apple = list.get(0); // Should be okay... but element 0 is an Orange! 

: 그것은 (멀리 컴파일러에 관한 한)에 유효 기간에 해당 있다고 찬성. 컴파일러는이 두 가지를 같은 방식으로 처리해야하므로 둘 다 무효화됩니다.

+0

안녕하세요. 설명 할 수 있니? 왜 안전하지 않니? 주황색 예제가 효과가있는 것처럼 보였습니다. 과일 목록에 오렌지를 추가해야합니다. – Jeb

+0

가장 중요한 과일 목록을 갖고 싶다면 해결책은 무엇입니까? – Jeb

+0

@ user450602 :하지만 실제로는 과일 목록이 아닙니다. 목록은 입니다. 자바는 타입 소거 때문에 말할 수 없다. 예제가 작동하지 않아야하는 이유를 더 자세히 보여주기 위해이 예제를 편집 해 보겠습니다. –

0

당신은

진짜 용어 contravariance입니다 :) 당신의 작은 문제가 큰 규모에 엄청난 파급 효과가 있기 때문에 나는이 문제에 대한 완전한 그림에 대한 component based software에이 슬라이드를 읽는 것이 좋습니다 정말 기술적 인 설명을 원하는 경우공분산. OO 설계와 대형 시스템에서의 한계와 관련하여 these slides에서 검색하십시오.

귀하의 문제가 :)

즉 혼합 일부 제네릭와 이들의 혼합이다, 계약 (과일보다 더 구체적 무언가의 과일입니다 뭔가) 목록이 있어야한다는 지정 과일의 모든 종류를 유지할 수 있지만 과일의 특정 종류 (사과보다 더 구체적인 사과를보다 구체적인), 어떤 컴파일러 오류를 발생시켜야하지만, 자바 - 컴파일러가 너무 좋고 제네릭이 제대로 구현되지 않았습니다. Java로 작성되었습니다 (시멘틱 스 및 인트로 스펙 션 관점에서).

컨테이너 인스턴스는 컨테이너 유형/클래스와 공변하거나 불변이지만 인스턴스의 containee는 containee 유형/클래스에 대한 불변 값이어야합니다.

구체적인 예 :

일반적인 예를
List<Fruit> list = new ArrayList<Fruit>(); 

: 개체가 모두 (공분산)에 넣고 검색 할 수 있기 때문에

ConatainerType<ElementOfList> list = new MoreSpecificContainerType<ElementOfList>(); 

ElementOfList 공분산 및 contravariance을 모두 충족해야한다 (contravariance) 그것은 불변성, 즉 같은 타입/클래스만을 남긴다.

이것은 정말 긴 대답 이었지만 앞으로는 비슷한 질문을하는 사람에게 도움이되기를 바랍니다.