2011-08-09 2 views
11

Java에서 매개 변수화 된 유형을 사용하는 경우 매개 변수가 바운드 작업 내에 있는지 확인하는 규칙은 어떻게 되나요? 와일드 카드의 경우 정확히?Java 제네릭 형식의 와일드 카드 매개 변수에 대한 공식 조건이 해당 범위 내에 있습니까?

이 같은 클래스를 감안할 때 :

class Foo<T extends Number> {} 

어떤 컴파일러가 받아들이는 것은 그 학습과 실험 :

관련되지 않은 인터페이스 유형을 사용하는 ? extends 와일드 카드가 허용됩니다
  • : Foo<? extends Runnable> 유효
  • A ? extends 관련없는 클래스 유형을 사용하는 와일드 카드는 허용되지 않습니다. Foo<? extends Thread>은 유효하지 않습니다. Runnable 하위 유형이 아니기 때문에 Foo<? super Runnable>이 허용되지 않습니다 : 어떤 유형이 ? super 와일드 카드에서 모두 NumberThread
  • 의 하위 유형이 될 수 없다, 와일드 카드의 하한이 유형 변수의 바인딩의 하위 유형이어야하기 때문 의미가 있습니다 Number입니다. 다시 말하지만,이 제한은 완벽합니다.

하지만이 규칙은 어디에 정의되어 있습니까? Java Language Specification section 4.5을 보면 클래스와 인터페이스를 구별하지 못합니다. JLS에 대한 나의 해석을 적용 할 때 Foo<? super Runnable>이 유효하다고합니다. 그래서 아마 뭔가 잘못 이해했을 것입니다. JLS의 섹션에서

: 여기 내 시도이다

파라미터 화 된 형태가 클래스 또는 인터페이스 이름 C의 구성과 실제의 형태 인수 목록 < T1, ..., 테네시>. C가 일반적인 클래스 또는 인터페이스의 이름이 아닌 경우 또는 실제 형식 인수 목록의 형식 인수 개수가 C의 선언 형식 매개 변수 개수와 다른 경우 컴파일 타임 오류가 발생합니다. 다음에서 우리가 말할 때마다 클래스 또는 인터페이스 유형의 경우 명시 적으로 제외되지 않는 한 일반 버전도 포함합니다. 이 절 전반에 걸쳐 A1, ..., An을 C의 공식 형식 매개 변수라고하고 Bi를 Ai의 선언 된 경계라고합시다. 표기법 [Ai : = Ti]는 유형 변수 Ai의 유형 Ti 로의 대체를 나타내며 1 < = i < = n이고 본 명세서에서 사용됩니다.

P = G < T1, ..., Tn>을 매개 변수화 된 유형으로 지정하십시오. P가 각각의 실제 형식 인수 Xi에 대해 유형 G < X1, ..., Xn>을 발생시키는 캡처 변환 (5.1.10)을받은 후에 1 < = i < = n 인 경우, Xi < : Bi [A1 : = X1, ..., An : = Xn] (§4.10) 또는 컴파일 시간 오류가 발생합니다. C = Foo, N = 1, T1 = ? super Runnable 및 B1 = Number 제공 :

는 P = Foo<? super Runnable> 해당 적용. 캡처 변환을위한

definition of capture conversion의이 부분은 적용

을 티 양식의 와일드 카드 형 인수가? super Bi이면 Si는 상한이 Ui [A1 : = S1, ..., An : = Sn]이고 하한이 Bi 인 신선한 유형 변수입니다., G < X1 제공

..., Xn에> = X 상한 Number와 새로운 입력 변수이며 Runnable를 하한 Foo<X>. 나는 그런 타입 변수를 명시 적으로 금지하는 것을 보지 못합니다.

B1 = Number에는 유형 변수가 없으므로 Bi [A1 : = X1, ..., An : = Xn]은 여전히 ​​간단하게 Number입니다. Number (= 동성 [A1 : (캡처 변환 으) 및 the subtyping rules에 따른 상한의 "형 변수를 직접 퍼 그 경계에 기재된 유형은"로 X 그래서, X <을 Number을 갖는다 = X1을 ..., An : = Xn]),이 매개 변수는 해당 범위 내에 있습니다.

동일한 추론에 따라 마다 와일드 카드가 해당 범위 내에 있으므로 여기에있는 어떤 것이 맞지 않습니다 ... 그러나이 추론은 정확히 어디에서 잘못 되었습니까? 어떻게 을 실행하면이 규칙이 올바르게 적용될 때 작동합니까?

답변

5

제네릭의 JLS가 불완전하고 다른 구멍을 발견했습니다. 타입 변수에 대한 하한은 간과해서는 안되며, 상한이 Number이고 하한이 RunnableX에 대한 스펙에는 제한이 없습니다. 그들은 아마 그것을 버렸습니다.

직관적으로 유형 변수의 상한과 하한을 모두 충족하는 가능한 유형이 하나 이상 있어야합니다. 그렇지 않으면 변수 및 변수를 사용하는 모든 유형이 쓸모가 없습니다. 이것은 거의 확실히 프로그래밍 실수이므로 컴파일이 실패해야합니다.

상한 및 하한이 비어있는 유형 집합인지 여부를 쉽게 확인 할 수 있습니다. 하한의 모든 슈퍼 타입은 알려져 있습니다. 그것들 중 적어도 하나는 상한이어야하며, 그렇지 않으면 두 경계 내에있는 유형이 없습니다.

-

은 두 Foo<? extends A> 경우 잘 스펙에 정의되어 있습니다. 캡처 변환, 우리는 상한 A & Number 새로운 형태 변수 X을 가지고 있고, 스펙에 대해 말한다 상위

V1&...&Vm 바운드

그것은 컴파일 타임 오류가있는 경우 두 개의 클래스 (안 인터페이스) VI와 자 Vi에 대한, Vi는 Vj의 서브 클래스가 아니거나 그 반대입니다.

따라서 A = Thread이면 캡처 변환이 실패합니다.