2013-02-28 6 views
6

그래서 개념을 다시 익히기 위해 제네릭을 읽었습니다. 특히 와일드 카드를 사용하는 곳이 거의 없었기 때문에 개념을 다시 익히거나 익숙하지 않았습니다. 내가했던 일에서 왜 그들이 와일드 카드를 사용하는지 이해할 수 없다. 제가 계속해서 제시하는 예 중 하나는 다음과 같습니다.Java 제네릭 : 와일드 카드

void printCollection(Collection<?> c) { 
    for (Object o : c){ 
    System.out.println(o); 
    } 
} 

왜 쓸 것이 아니라 :

<T> void printCollection(Collection<T> c) { 
    for(T o : c) { 
     System.out.println(o); 
    } 
} 

오라클 웹 사이트에서 또 다른 예 : 왜이 ​​

public static <T extends Number> double sumOfList(List<T> list) { 
    double s = 0.0; 
    for (Number n : list) 
     s += n.doubleValue(); 
    return s; 
} 

암으로 기록되지 않습니다

public static double sumOfList(List<? extends Number> list) { 
    double s = 0.0; 
    for (Number n : list) 
     s += n.doubleValue(); 
    return s; 
} 

나는 무엇인가 놓친다?

+0

가능 [복제] (http://stackoverflow.com/questions/10943137/difference-between-generic-type-and-wildcard-type) – Jayamohan

+1

@Jayamohan 나는 동의하지 않습니다. –

답변

3

: 나는 일반적인 방법을 사용해야 할 때, 그리고 때 와일드 카드 형식을 사용해야입니다 발생

질문 하나? 해답을 이해하기 위해 Collection 라이브러리에서 몇 가지 메소드를 살펴 보자.

interface Collection<E> { 
    public boolean containsAll(Collection<?> c); 
    public boolean addAll(Collection<? extends E> c); 
} 

우리가 사용할 수도 일반적인 방법 대신 여기가 :

interface Collection<E> { 
    public <T> boolean containsAll(Collection<T> c); 
    public <T extends E> boolean addAll(Collection<T> c); 
    // Hey, type variables can have bounds too! 
} 

그러나, containsAll 나 및 오퍼레이션과 addAll 모두에서 유형 매개 변수 T는 한 번만 사용됩니다. 반환 유형은 type 매개 변수에 의존하지 않으며 메서드에 대한 다른 인수도 없습니다 (이 경우에는 단 하나의 인수 만 있음). 이것은 타입 인자가 다형성을 위해 사용되고 있다는 것을 말해줍니다; 그것의 유일한 효과는 다양한 호출 유형에서 다양한 실제 인수 유형을 사용할 수있게하는 것입니다. 이 경우 와일드 카드를 사용해야합니다. 와일드 카드는 여기에 표현하려고하는 유연한 하위 유형 지정을 지원하도록 설계되었습니다.

첫 번째 예는 작업이 유형에 의존하지 않기 때문입니다.

두 번째로는 Number 클래스에만 의존하기 때문입니다.

+0

고마워, 모든 설명은 좋았지 만, 어떤 이유에서이 설명이 나를 가장 잘 이해하는 데 도움이되었다. –

3

왜 물건을 필요 이상으로 복잡하게 만드나요? 예제에서는 the simplest thing that could possibly work을 보여줍니다.이 예제는 일반적인 방법을 설명하지는 않습니다. 객체를 받아 들일 수

<T> void printCollection(Collection<T> c) { 
    for(T o : c) { 
     System.out.println(o); 
    } 
} 

System.out.println() 때문에, 그래서 아무것도 더 특정이 필요하다 :

왜 당신은이를 쓸 것입니다. 당신이 모든 다른 T extends Number에 대해 서로 다른 파라미터를 필요로하지 않기 때문에

는 왜 이런 일이, 다시

public static <T extends Number> double sumOfList(List<T> list) { 
    double s = 0.0; 
    for (Number n : list) 
     s += n.doubleValue(); 
    return s; 
} 

로 기록되지 않습니다. List<? extends Number>을 허용하는 비 제네릭 방법이면 충분합니다.

+0

나는 두 사람의 차이를 오해하고 있을지도 모른다고 생각합니까? 아니면 똑같습니까? 내가 어떤 상황에 빠지면 T가 아닌 T를 사용하여 해결할 수 없습니까? 나는 와일드 카드의 요점을 완전히 놓치고 있다고 느낍니다. –

+2

@ 존 테일러 (JonTaylor) :''''대신''T ''로 해결할 수없는 상황은 없지만'?'는 이름이 필요 없으며 당신이 정말로 신경 쓰지 않는다는 것을 의미합니다 어떤 종류인가. –

+0

@LouisWasserman'Class '을 반환하는'Class.forName'은 와일드 카드 만 적절하다는 예일 수 있습니다. –

3

메소드 매개 변수 유형이 상한이있는 첫 번째 레벨 와일드 카드를 가지면 유형 매개 변수로 대체 될 수 있습니다.

카운터 예 (와일드 카드는 입력 매개 변수로 대체 될 수있다)이 일반적이라고 생각된다

 void foo1(List<?> arg) 

    <T> void foo2(List<T> arg) 

어느 와일드 또는 타입 파라미터에 의해 해결 될 수있는 경우 지금

List<?> foo() // wildcard in return type 

    void foo(List<List<?>> arg) // deeper level of wildcard 

    void foo(List<? super Number> arg) // wildcard with lower bound 

foo1()foo2()보다 세련되어 있습니다. 아마 약간 주관적 일 것입니다. 나는 개인적으로 foo1() 서명이 더 이해하기 쉽다고 생각한다. 그리고 foo1()은 업계에서 압도적으로 채택되어 있으므로 국제 대회를 준수하는 것이 좋습니다.

foo1()arg.add(something)foo1()에 쉽게 입력 할 수 없으므로 좀 더 추상적으로 처리합니다. 물론 쉽게 해결할 수 있습니다 (즉, arg를 foo2()으로 전달하십시오!). 공용 메서드가 내부적으로 전용 foo2()으로 이동하는 foo1()처럼 보이는 것도 일반적인 방법입니다.

또한 와일드 카드하지 않을 경우가 있습니다 및 유형 매개 변수가 필요합니다 :

<T> void foo(List<T> foo1, List<T> foo2); // can't use 2 wildcards. 

이 논의는 지금까지 메소드 서명에 관한 것입니다. 다른 곳에서는 형식 매개 변수를 입력 할 수없는 곳에서는 와일드 카드가 필수적입니다. Oracle에서

+0

+1 유형 매개 변수에 [낮은 경계를 지정할 수 없음]을 언급하기 위해 (http://stackoverflow.com/questions/2800369/bounding-generics-with-super-keyword). –