답변:
첫 두 개 사이에는 차이가 없습니다. 형식 매개 변수 ( E
또는 T
)에 다른 이름을 사용하고 있습니다.
세 번째는 유효한 선언하지 않습니다 - ?
A와 사용되는 와일드 카드 타입 제공 할 때 사용되는 인수를 , 예를 들어 List<?> foo = ...
그 방법을 foo
몇 가지 유형의 목록을 의미하지만, 우리는 무엇을 알고하지 않습니다.
이 모든 것이 제네릭 이며 꽤 큰 주제입니다. 물론 더 많은 자료가 있지만 다음 자료를 통해 그것에 대해 배우고 싶을 수도 있습니다.
T
하고 E
- 그들은 단지 식별자입니다. KeyValuePair<K, V>
예를 들어 쓸 수 있습니다. ?
그래도 특별한 의미가 있습니다.
이전 답변에서는 유형 매개 변수 (T, E 등)에 대해 설명했지만 와일드 카드, "?"또는 이들 사이의 차이점에 대해서는 설명하지 않으므로 이에 대해 설명하겠습니다.
먼저, 명확하게 말하면 와일드 카드와 유형 매개 변수는 동일하지 않습니다. 유형 매개 변수가 범위의 유형을 나타내는 일종의 변수 (예 : T)를 정의하는 경우 와일드 카드는 그렇지 않습니다. 와일드 카드는 일반 유형에 사용할 수있는 허용 가능한 유형 세트 만 정의합니다. 경계없이 (extends
또는 super
)가 와일드 카드는 "여기에 모든 유형 사용"을 의미합니다.
와일드 카드는 항상 꺾쇠 괄호 사이에 있으며 일반 유형의 컨텍스트에서만 의미가 있습니다.
public void foo(List<?> listOfAnyType) {...} // pass a List of any type
못
public <?> ? bar(? someType) {...} // error. Must use type params here
또는
public class MyGeneric ? { // error
public ? getFoo() { ... } // error
...
}
겹치는 부분이 더 혼란스러워집니다. 예를 들면 다음과 같습니다.
List<T> fooList; // A list which will be of type T, when T is chosen.
// Requires T was defined above in this scope
List<?> barList; // A list of some type, decided elsewhere. You can do
// this anywhere, no T required.
메소드 정의에서 가능한 것과 겹치는 부분이 많이 있습니다. 다음은 기능적으로 동일합니다.
public <T> void foo(List<T> listOfT) {...}
public void bar(List<?> listOfSomething) {...}
겹치는 부분이 있다면 왜 다른 것을 사용합니까? 때로는 정직한 스타일 일 수도 있습니다. 어떤 사람들은 타입 매개 변수 가 필요 하지 않으면 코드를 더 단순하고 읽기 쉽게하기 위해 와일드 카드를 사용해야 한다고 말합니다 . 위에서 설명한 한 가지 주요 차이점 : 형식 매개 변수는 범위의 다른 곳에서 사용할 수있는 형식 변수 (예 : T)를 정의합니다. 와일드 카드는 그렇지 않습니다. 그렇지 않으면, 유형 매개 변수와 와일드 카드 사이에는 두 가지 큰 차이점이 있습니다.
형식 매개 변수는 여러 바인딩 클래스를 가질 수 있습니다. 와일드 카드는 다음을 수행 할 수 없습니다.
public class Foo <T extends Comparable<T> & Cloneable> {...}
와일드 카드는 하한을 가질 수 있습니다. 유형 매개 변수는 다음을 수행 할 수 없습니다.
public void bar(List<? super Integer> list) {...}
위의 List<? super Integer>
정의 Integer
는 와일드 카드에서 하한으로 정의 됩니다. 즉, List 유형은 Integer 또는 Super-Integer 유형이어야합니다. 제네릭 형식 경계는 자세히 다루고 싶지 않습니다. 즉, 어떤 유형 을 정의 할 수 있습니다 일반 유형이 될 수 할 수 있습니다. 이를 통해 제네릭을 다형성으로 처리 할 수 있습니다. 예 :
public void foo(List<? extends Number> numbers) {...}
당신은을 전달할 수 있습니다 List<Integer>
, List<Float>
,List<Byte>
, 등numbers
. 유형 경계가 없으면 작동하지 않습니다. 즉, 제네릭의 방식입니다.
마지막으로 와일드 카드를 사용하여 다른 방법으로는 할 수없는 일을하는 메소드 정의가 있습니다.
public static <T extends Number> void adder(T elem, List<? super Number> numberSuper) {
numberSuper.add(elem);
}
numberSuper
번호의 목록 또는 번호 (예를 들어, 어떤 슈퍼 될 수 있습니다 List<Object>
), 그리고 elem
번호 또는 하위 유형이어야합니다. 모든 경계에서 컴파일러는 형식 .add()
이 안전한지 확인할 수 있습니다 .
유형 변수 <T>는 사용자가 지정하는 기본이 아닌 유형 (예 : 모든 클래스 유형, 인터페이스 유형, 배열 유형 또는 다른 유형 변수) 일 수 있습니다.
가장 일반적으로 사용되는 유형 매개 변수 이름은 다음과 같습니다.
Java 7에서는 다음과 같이 인스턴스화 할 수 있습니다.
Foo<String, Integer> foo = new Foo<>(); // Java 7
Foo<String, Integer> foo = new Foo<String, Integer>(); // Java 6