'E', 'T'및 ''의 차이점은 무엇입니까? Java 제네릭의 경우


261

다음과 같은 Java 코드를 발견했습니다.

public interface Foo<E> {}

public interface Bar<T> {}

public interface Zar<?> {}

위의 세 가지 차이점은 무엇이며 Java에서 이러한 유형의 클래스 또는 인터페이스 선언이라고하는 것은 무엇입니까?


1
나는 어떤 차이가 있는지 의심한다. 그 유형 매개 변수의 이름 일뿐입니다. 그리고 마지막 것은 유효합니까?
코드 InChaos

답변:


231

첫 두 개 사이에는 차이가 없습니다. 형식 매개 변수 ( E또는 T)에 다른 이름을 사용하고 있습니다.

세 번째는 유효한 선언하지 않습니다 - ?A와 사용되는 와일드 카드 타입 제공 할 때 사용되는 인수를 , 예를 들어 List<?> foo = ...그 방법을 foo몇 가지 유형의 목록을 의미하지만, 우리는 무엇을 알고하지 않습니다.

이 모든 것이 제네릭 이며 꽤 큰 주제입니다. 물론 더 많은 자료가 있지만 다음 자료를 통해 그것에 대해 배우고 싶을 수도 있습니다.


1
PDF에 대한 링크가 끊어진 것 같습니다. 나는 여기 에 사본으로 보이는 것을 찾았 지만 원본이 어떻게 생겼는지 모르기 때문에 100 % 확신 할 수 없습니다.
John

2
@ 존 : 예, 그게 하나입니다. 하나 또는 Oracle 하나의 링크를 편집합니다 ...
Jon Skeet

T, E 및 이외의 다른 것이 있습니까? 제네릭에 사용됩니까? 그렇다면 무엇이며 무엇을 의미합니까?
sofs1

1
@ sofs1 : 거기에 대해 아무것도 특별 T하고 E- 그들은 단지 식별자입니다. KeyValuePair<K, V>예를 들어 쓸 수 있습니다. ?그래도 특별한 의미가 있습니다.
Jon Skeet

215

다른 것보다 더 많은 관습입니다.

  • T 유형이 될 것입니다
  • E요소 (요소 List<E>의 목록)
  • K키 ( Map<K,V>)
  • V 값 (반환 값 또는 맵핑 된 값)

그것들은 완전히 상호 교환 가능합니다 (같은 선언에도 불구하고 충돌합니다).


20
<> 사이의 문자는 단지 이름입니다. 당신의 대답에서 묘사하는 것은 단지 관습입니다. 단일 대문자 일 필요는 없습니다. 클래스, 변수 등 원하는 이름을 지정할 수있는 것처럼 원하는 이름을 사용할 수 있습니다.
Jesper


6
당신은 물음표를 설명하지 않았습니다. 공감.
신주

129

이전 답변에서는 유형 매개 변수 (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()이 안전한지 확인할 수 있습니다 .


"public void foo (List <? extends Number> numbers) {...}" "extends"는 "super"여야합니까?
1a1a11a

1
아니요.이 예제의 요점은 숫자 목록과 숫자의 하위 유형을 다형성 적으로 지원하는 서명을 보여주는 것입니다. 이를 위해 "extends"를 사용합니다. 즉, "숫자 목록 또는 숫자 를 확장하는 모든 항목을 전달하십시오 "(List <Integer>, List <Float> 등). 이와 같은 메소드는 목록을 반복하고 각 요소에 대해 "e"를 실행합니다 (예 : e.floatValue ()). 전달하는 Number의 하위 유형 (확장자)은 중요하지 않습니다. .floatValue ()는 Number의 메소드이므로 항상 ".floatValue ()"를 사용할 수 있습니다.
Hawkeye Parker

마지막 예제에서 "List <? super Number>"는 메서드가 더 일반적인 것을 허용하지 않기 때문에 단순히 "List <Number>"일 수 있습니다.
jessarah

@jessarah nope. 어쩌면 내 예제가 명확하지 않지만 예제에서 adder ()가 List <Object>를 취할 수 있다고 언급했습니다 (Object는 Number의 수퍼 클래스입니다). 이 작업을 수행하려면 "List <? super Number>"서명이 있어야합니다. 이것이 바로 "슈퍼"의 요점입니다.
Hawkeye Parker

2
이 답변은 와일드 카드와 유형 매개 변수의 차이점을 설명하는 데 매우 유용합니다.이 답변에는 하나의 전용 질문이 있어야합니다. 나는 최근에 제네릭에 더 깊이 들어가고 있으며이 답변은 여러 가지 정확한 정보를 요약하는 데 도움이되었습니다. 감사합니다!
Testo Testini

27

유형 변수 <T>는 사용자가 지정하는 기본이 아닌 유형 (예 : 모든 클래스 유형, 인터페이스 유형, 배열 유형 또는 다른 유형 변수) 일 수 있습니다.

가장 일반적으로 사용되는 유형 매개 변수 이름은 다음과 같습니다.

  • E-요소 (Java Collections Framework에서 광범위하게 사용)
  • K-키
  • N-숫자
  • T-유형
  • V-가치

Java 7에서는 다음과 같이 인스턴스화 할 수 있습니다.

Foo<String, Integer> foo = new Foo<>(); // Java 7
Foo<String, Integer> foo = new Foo<String, Integer>(); // Java 6

3

가장 일반적으로 사용되는 유형 매개 변수 이름은 다음과 같습니다.

E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types

이 이름은 Java SE API 전체에서 사용됩니다.


2

컴파일러는 다음과 같은 기능을 구성 할 때 각 와일드 카드 (예 : List의 물음표)를 캡처합니다 .

foo(List<?> list) {
    list.put(list.get()) // ERROR: capture and Object are not identical type.
}

그러나 V와 같은 일반적인 유형은 괜찮고 일반적인 방법으로 만듭니다 .

<V>void foo(List<V> list) {
    list.put(list.get())
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.