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?
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?
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.
Jeden dodatkowy przykład: http://stackoverflow.com/questions/4449611/can-anyone-give-me-an-example-where-the-eclipse-jdt-creates-an-ast-wcaptur –
@ John, jeśli przeczytasz artykuł (link podany powyżej z IBMWorks), zobaczysz, że podany przez ciebie przykład pochodzi stąd. –
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
Brak przykłady innych niż w dyskusji bezpośrednio poniżej? –
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. –