2010-12-13 12 views
13

Zauważyłem, że JLS mówi o 5.1.10 Capture Conversion, ale nie rozumiem, czym one są.Co to jest konwersja przechwytywania w Javie i czy ktoś może podać mi przykłady?

Czy ktoś może mi je wytłumaczyć/podać przykłady?

+0

Brak przykłady innych niż w dyskusji bezpośrednio poniżej? –

+0

To prawda, stanowią przykład, ale z tego nie mogłem zrozumieć, jakie konwersje przechwytywania są. Czy zrozumiałeś przykład? Jeśli tak, czy możesz mi uprzejmie wyjaśnić, czym one są. Dzięki. –

Odpowiedz

18

Konwersja przechwytywania została zaprojektowana, aby użyteczne były symbole wieloznaczne (w generycznych), ?.

Załóżmy, że mamy następujące klasy:

public interface Test<T> { 
    public void shout(T whatever); 
    public T repeatPreviousShout(); 

} 

i gdzieś na naszym kodzie mamy,

public static void instantTest(Test<?> test) { 
    System.out.println(test.repeatPreviousShout()); 
} 

Ponieważ test nie jest surowy Test a od repeatPreviousShout() w "celownik" zwraca ? kompilator wie, że istnieje T, który służy jako parametr typu dla Test. To jest dla nieznanego T dla nieznanych T, więc kompilator kasuje nieznany typ (dla symboli wieloznacznych, zastępuje się Object)., Dlatego repeatPreviousShout() zwraca Object.

Ale gdybyśmy mieli,

public static void instantTest2(Test<?> test) { 
    test.shout(test.repeatPreviousShout()); 
} 

Kompilator da nam błąd, coś jak Test<capture#xxx of ?> cannot be applied (gdzie xxx jest liczbą, np 337).

To dlatego, że kompilator próbuje wykonać kontrolę bezpieczeństwa typ na shout() ale ponieważ otrzymał dziką kartę, to nie wiem, co T reprezentuje, dlatego tworzy zastępczy zwany wychwytywania.

Od here (Java theory and practice: Going wild with generics, Part 1), wyraźnie stwierdza:

przechwytywania konwersji jest tym, co pozwala kompilator produkować zastępczy nazwę typu dla przechwyconego zamiennika, tak że typ wnioskowanie można wywnioskować go być tego typu .

Mam nadzieję, że to pomoże.

+0

Jeden dodatkowy przykład: http://stackoverflow.com/questions/4449611/can-anyone-give-me-an-example-where-the-eclipse-jdt-creates-an-ast-wcaptur –

+0

@ John, jeśli przeczytasz artykuł (link podany powyżej z IBMWorks), zobaczysz, że podany przez ciebie przykład pochodzi stąd. –

1

Sparametryzowany typ z argumentami typu wieloznacznego jest naprawdę typem złączowym. Na przykład

List<? extends Number> = Union{ List<S> | S <: Number } 

u 2, zamiast zastosowania List<? extends Number> Java stosuje przechwycony wersji List<S>, gdzie S jest rodzajem tak utworzony zmienną górna granica Number.

(1) http://java.sun.com/docs/books/jls/third_edition/html/expressions.html

Aby zmienić typ wyrażenia. Jeśli typem wyrażenia jest List<? extends Number>, wiemy na pewno, że typ środowiska wykonawczego obiektu faktycznie jest List<S> dla konkretnego typu betonu S (S <: Number>). Dlatego kompilator używa zamiast niego List<S>, aby wykonać dokładniejszą analizę typu.

Konwersja przechwytywania jest stosowana do każdego wyrażenia osobno; Prowadzi to do jakichś głupich wyników:

<T> void test1(List<T> a){} 
<T> void test2(List<T> a, List<T> b){} 

List<?> x = ...; 
test1(x); // ok 
test2(x, x); // error 

(2) http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.10.2

W podtypu sprawdzanie A :< B gdzie A wiąże wieloznacznych argumenty. Na przykład,

List<? extends Number> :< B 
<=> 
Union{ List<S> | S <: Number} :< B 
<=> 
List<S> :< B, for all S <: Number 

więc w efekcie mamy do sprawdzenia przechwycony wersję typu A

Powiązane problemy