2010-12-02 17 views
10

이유는 무엇입니까 선언중첩 형식 인수는 어떻게 작동합니까?

Set<Set<String>> var = new HashSet<Set<String>>(); 

작업하지만, 선언

Set<Set<String>> var = new HashSet<HashSet<String>>(); 

초크?

선언의 제네릭이 괄호 안에있는 규칙과 다른 규칙으로 작동하는 '최상위 수준'(올바른 문구인지 확실하지 않음)을 알고 있지만 그 이유를 알고 싶습니다. Google에 쉬운 질문이 아니기 때문에 나는 너희들을 시험해 볼 것이라고 생각했다.

답변

12

허용 된 경우 입력 시스템을 우회 할 수 있기 때문입니다. 당신이 원하는 재산은 covariance입니다. 컬렉션이 공변 인 경우에 당신은이 작업을 수행 할 수있을 것입니다 :

Set<Set<String>> var = new HashSet<HashSet<String>>(); 

var.add(new TreeSet<String>()); 

TreeSet의 세트의 유형입니다, 그래서 정적 타입 검사는 VAR에 TreeSet의 삽입되지 않도록하지 않을 것입니다. 그러나 var은 HashSet 및 HashSets 만 예상하며 이전 유형의 Set은 기대하지 않습니다.

는 개인적으로, 나는 항상 첫 번째 선언을 쓰기 :

Set<Set<String>> var = new HashSet<Set<String>>(); 

외부 클래스는 conrete 구현을 가질 필요가 있지만, 특히 HashSet의 위해 내부 클래스를 못 할 필요는 보통 없습니다. 집합의 HashSet을 만들면 잘 수행 할 수 있습니다. var에 일련의 HashSet을 삽입하려고하면 나중에 프로그램에서 선택할 수 있지만 선언을 제한 할 필요는 없습니다.

그것은 가치가 무엇인지에 대한

, 자바 의 배열은 컬렉션 클래스와는 달리, 공변입니다. 이 코드는 컴파일되고 컴파일 타임에 잡히지 않고 런타임 예외를 발생시킵니다.

// Arrays are covariant, assignment is permitted. 
Object[] array = new String[] {"foo", "bar"}; 

// Runtime exception, can't convert Integer to String. 
array[0] = new Integer(5); 
3

Java에서 제네릭이 작동하는 방식 때문입니다.

Set<? extends Set<String>> var = new HashSet<HashSet<String>>(); 
+3

이 대답은 나에게 많은 의미가 없습니다. John Kugelman과 ColinD는이 문제를 명확하게 설명합니다. – erickson

+2

이것은 type 매개 변수를 "추론"하는 것과 아무런 관련이 없습니다. – ColinD

+0

@ColinD : 수정하십시오. 결정된. – haylem

0

차이점은 var는 유형 Set<String> (이 중 HashSetSet이다)의 값을 수용 할 수있는 Set<Set<String>> var = new HashSet<Set<String>> 수 있도록함으로써, 간단합니다. var의 내부 유형 Set<String>를 기대 때문이 아니라 Set<Set<String>> var = new HashSet<HashSet<String>>();에 관해서는

뿐만 아니라,이 컴파일되지 않습니다, 그것은 HashSet<String> 찾습니다. 이 경우 var.add(new TreeSet<String>());은 오류가있을 수 있습니다 (유형 비 호환성은 HashSetTreeSet 사이입니다).

희망이 도움이됩니다.

+2

'Set > '는 외부 세트가'null'을 제외하고는 아무것도 허용하지 않지만'Set '을 포함한다는 것을 의미합니다. – ColinD

+0

그리고'Set >'은''Set '의 모든 구현자를 ("add()'*가 허용하는"* "을 의미한다. Set는 심지어 구체적인 클래스가 아니기 때문에,'Set >'가'Set '의 서브 타입을 취하지 않으면 쓸모가 없다. –

+0

@ColinD & Mark Peters, 지적 .... 내 게시물을 다시 업데이트했습니다. –

7

이유는 Set<Set<String>>Set<HashSet<String>>과 같지 않기 때문입니다! Set<Set<String>>임의의 유형 Set<String>을 포함 할 수 있으며, Set<HashSet<String>>HashSet<String> 만 포함 할 수 있습니다.Set<Set<String>> set = new HashSet<HashSet<String>>() 법적 있었다

경우에는 오류없이이 작업을 수행 할 수 있습니다 :

Set<? extends Set<String>> set = setOfHashSets; 

이 이제 때문에 허용된다 :

Set<HashSet<String>> setOfHashSets = new HashSet<HashSet<String>>(); 
Set<Set<String>> set = setOfHashSets; 
set.add(new TreeSet<String>()); 
HashSet<String> wrong = set.iterator().next(); // ERROR! 

그것은, 그러나, 법적 여기에 경계 와일드 카드를 사용하는 것입니다 , 집합에 포함 된 객체의 유형은 ? extends Set<String> ... 다른 말로하면 "알 수없는 클래스를 구현하는 Set<String> 클래스"입니다. Set<String>의 특정 유형이 무엇을 포함하고 있는지 정확히 알지 못하므로 아무 것도 추가 할 수 없습니다 (null 제외) ... 잘못된 것일 수 있습니다. 나중에 내 오류가 발생합니다. 첫 번째 예.

편집 :

참고 귀하의 질문에 당신이 참조하는 "최상위 수준"제네릭 하나 이상의 유형 매개 변수을 유형을 의미 매개 변수 유형라는 것을. Set<Set<String>> set = new HashSet<Set<String>>()이 합법적 인 이유는 HashSet<T>Set<T>을 구현하므로 하위 유형Set<T>입니다. 그러나 형식 매개 변수 T은 일치해야합니다. 유형이 S이고 유형이 T 인 경우 HashSet<S> (또는 Set<S> even)은 Set<T>의 하위 유형이 아닙니다! 위의 이유를 설명했습니다.

여기 정확히 상황입니다. 우리가 여기 TSet<String>를 교체 할 경우

Set<Set<String>> set = new HashSet<Set<String>>(); 

, 우리는 Set<T> set = new HashSet<T>()를 얻을. 따라서 실제 유형 인수이 관련되어 있고 할당 오른쪽에있는 유형이 왼쪽에있는 유형의 부속 유형이라는 것을 쉽게 알 수 있습니다.

Set<Set<String>> set = new HashSet<HashSet<String>>(); 

는 여기에서 우리는 ST의 하위 유형입니다 각각 TSSet<String>HashSet<String>를 교체해야합니다. 완료되면 Set<T> set = new HashSet<S>()이됩니다. 위에서 설명한대로 HashSet<S>은 하위 유형이 Set<T>이 아니므로 할당이 올바르지 않습니다.

0

은 첫 번째 줄은 법적 자바 코드 공변 배열과 코드입니다

//Array style valid an Integer is a Number 
Number[] numArr = new Integer[10] 
//Generic style invalid 
List<Number> list1 = new ArrayList<Integer>(); 
//Compiled (erased) List valid, pre generics (java 1.4) 
List list2 = new ArrayList(); 

간단하게 뭔가에 예를 줄일 수 있습니다. 다음 줄에는 List of Integer and Number에 대한 간단한 예제가 들어 있습니다. 마지막 줄에는 유효하지 않은 일반 목록이 있습니다.

는 ^^ 1.5 나에게 합리적인 숫자 것 같아, 우리의 숫자에 항목을 추가 할 수 있습니다

//this will compile but give us a nice RuntimeException 
numArr[0] = 1.5f 
//This would compile and thanks to type erasure 
//would even run without exception 
list1.add(1.5f) 

들이 RuntimeException이 유효 코드에서 발생하지해야하지만, 하나 보라 것처럼 numArr 숫자 만 정수를 개최 할 수 . generics는이 변수가 공 변하지 않으므로 컴파일 타임에이 오류를 포착합니다.

숫자와 정수의 이러한 목록을 동일한 것으로 허용 할 수없는 이유는 다음과 같습니다. 두 목록에서 제공하는 메서드는 서로 다른 인수를 받아들이므로 Integer 목록은 Integer 만 받아들이면 더 제한됩니다. 즉, 두 목록에서 제공하는 인터페이스는 호환되지 않습니다. 당신의 설정

Set<Set<String>>.add(Set<String> s) 
HashSet<HashSet<String>>.add(HashSet<String> s) 

추가 기능 및 두 종류의 다른 방법에 대한

List<Number>.add(Number n) 
List<Integer>.add(Integer n) 

같은이 유효 호환되지 않습니다.

(답변시 두 번째 시도, 이번에는 누군가를 읽지 않았 으면 함)

관련 문제