2011-05-02 3 views
6

여기에 무슨 일이 일어나고 있는지에 관해서는 저에게 힌트를주십시오 캡처 충돌 :팬시 제네릭

List<? extends Number> a = new ArrayList<Number>(); 
List<? extends Number> b = new ArrayList<Number>(); 

a.addAll(b); // ouch! compiler yells at me, see the block below: 
/* 
    incompatible types 
    found : java.util.List<capture#714 of ? extends java.lang.Number> 
    required: java.util.List<java.lang.Number> 
*/ 

이 간단한 코드는 컴파일되지 않습니다. 나는 캡쳐와 관련된 뭔가를 막연하게 기억하고있다. 실제 코드가 아닌 인터페이스 스펙에 주로 사용되어야하는 것과 같은 형식 캡쳐와 관련이있다. 그런 식의 어리석은 일은 결코 없다. 물론

그렇게, 짐승 - 강제로 고정 될 수 있습니다

List<? extends Number> a = new ArrayList<Number>(); 
List<? extends Number> b = new ArrayList<Number>(); 

@SuppressWarnings({"unchecked"}) 
List<Number> aPlain = (List<Number>) a; 
@SuppressWarnings({"unchecked"}) 
List<Number> bPlain = (List<Number>) b; 

aPlain.addAll(bPlain); 

그래서, 어떻게 내가 정말 (캡처가 인터페이스에서 나에게 와서 선언에 캡처를 포기 중 하나가, 그래서 일부 API를 변경해야 할 것입니다.) 또는 억제 주석이있는 타입 캐스트 (일반적으로 코드를 빨아 들이고 코드를 약간 복잡하게합니다)를 사용합니까?

+0

하이의 슈퍼 타입 이다 Object 형식의 값에 대한 제외하고 SUPER 와일드 카드로 선언 된 유형에서 무엇을 얻을, 왜 그냥 목록'로'A'를 선언하지= 새로운 ArrayList ()'? – Axel

+0

글쎄, 나는 List를 나에게 돌려 줄 때 이미이 캡쳐를 선언 한 API를 가지고있다. 나는 물건을 더 단순하게 유지하면서 생성자를 조금 더 (애매하게) 보이지 않게 만드는 데에만 사용한다. –

답변

9

본질적으로 서로 다른 유형의 목록이 두 가지 있습니다. ? extends NumberNumber을 확장하는 클래스를 의미하기 때문에. 따라서 a 목록의 경우 classA 일 수 있고 목록의 경우 b 일 수 있습니다. 예를 들어 classB 일 수 있습니다. 그들은 호환되지 않습니다, 그들은 완전히 다를 수 있습니다. 컴파일러는 실제의 형태 매개 변수는 추가 작업을하지 못하게 따라서이며, 무엇 List<? extends Number>에서 말할 수

List<? extends Number> a = new ArrayList<Integer>(); 
List<? extends Number> b = new ArrayList<Double>(); 

a.addAll(b); //ouch, would add Doubles to an Integer list 

:

+1

당신은 미끼로 의견을 말하고 있습니다. 나는 대답하기 전에 그 의견에 답하고 싶었다. 이제 댓글이 없어지고 대신 답장을 보냅니다. ;) – musiKk

+0

@musiKk - 하하하, 모든 것이 계획되었습니다;) –

+0

이것은 어떻게 든 공분산 형태와 관련이 있습니다. 아마도 예제 자체 (addAll 연산)는 다소 제한적이지만, 컬렉션에있는 객체에 equals() 및 hashCode()가 정의되어있는 한 모든 컬렉션 연산을 수행 할 수 있어야합니다. _UPD_ : 사실, Java는 이와 관련하여 다음과 같이 제한적입니다. 직접 와일드 카드를 만들 수 없습니다. new ArrayList (); // awuch! .. –

6

문제는 당신이 사용하는 경우 List<? extends Number> 당신이 실제로 할 수 있다는 것입니다.

매개 변수로 가져 오는 경우 목록을 List<Number>으로 캐스팅하지 않아야합니다. 실제로 정수 개체 목록을 포함하고 Double 개체를 추가 할 수 있기 때문입니다. 이 경우

당신은 더 나은 두 목록에서 개체를 새로운 List<Number>를 생성하고 추가

List<Number> c = new ArrayList<Number>(a.size() + b.size()); 
c.addAll(a); 
c.addAll(b); 

편집 : 로컬 모두 목록을 만들 경우, 당신은 ('당신 때문에 어쨌든 ? 와일드 카드를 NEET 않을 것 d는 항상 List<Number>입니다).

+0

음 ... 해결 방법 코드가 올바르지 않습니다. 아이디어는 캡처 된 두 개의 목록을 얻었 기 때문에 아이디어를 반영하기 위해 코드를 다시 코딩했습니다. –

+1

오해를 막기 위해 "해결 방법"에 대한 내 의견을 삭제했습니다. – Thomas

3

와일드 카드 ?을 사용하지 마십시오. 그것은 "내가 모르는 특정 유형"을 의미하며 유형을 모르기 때문에 목록에 아무 것도 추가 할 수 없습니다. List<Number>을 사용하도록 코드를 변경하면 모든 것이 작동합니다.

빠른

+0

그래, 그래,하지만 와일드 카드를 사용하는 일반적인 가이드는 무엇입니까? –

+1

@Anton : 여기에 더 자세한 설명이 나와 있습니다. http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#What%20is%20a%20wildcard? 그러나 일반적으로 와일드 카드는 드문 경우에만 유용합니다. –

1

것은입니다 ... 백 변화에 가장 자주 묻는 자바 문제가되고있다 :

List<? extends Number> a = new ArrayList<Number>(); 
List<? extends Number> b = new ArrayList<Number>(); 

도 읽을 수로 :

List<x extends Number> a = new ArrayList<Number>(); 
List<y extends Number> b = new ArrayList<Number>(); 

컴파일러는 x와 y가 같은 것을 어떻게 알 수 있습니까?

+0

글쎄, 나는 컴파일러가 필요한 모든 정보를 가지고 있다고 확신했다. 그렇지 않은 경우 ... :) –

2

PECS이

  • 당신이 선언 형식에 아무것도 넣지 수 (소비자 슈퍼, 생산자 - 확장) 모든 참조 형에 속하는 null 값을 제외하고 와일드 카드 를 확장
  • 당신은 할 수 없습니다 모든 참조 형