2014-10-08 16 views
10

Mam 3 następujące testy. Dwie pierwsze prace, ostatnia nie. Moja motywacja do zadawania tego pytania polega na tym, że chciałbym móc rzucić obiekt A, tak aby miał tę samą klasę co obiekt B, kiedy A jest znany jako podtyp B.Dlaczego casting oparty na Class.class działa, ale nie działa getClass?

@Test 
    public void testWorks() { 
    Object bar = "foobar"; 
    String blah = (String) bar; 
    System.out.println(blah); // Outputs foobar 
    } 

    @Test 
    public void testAlsoWorks() { 
    Object bar = "helloworld"; 
    String blah = String.class.cast(bar); 
    System.out.println(blah); // Outputs helloworld 
    } 

    @Test 
    public void testfails() { 
    Object bar = "foobar"; 
    String thetype = "hello"; 
    Class stringclass = thetype.getClass(); 
    String blah = stringclass.cast(bar); // Compiler error: incompatible types: Object cannot be converted to String                            
    System.out.println(blah); 
    } 

Czy ktoś może wyjaśnić, dlaczego ostatni przypadek się nie powiódł, gdy pierwsze dwa powiodły się i dlaczego tak się dzieje? I jakie byłoby lepsze podejście, aby to osiągnąć?

+0

Zakładam, że klasa .class jest oceniana podczas kompilacji, ale metoda .getClass() jest oceniana w czasie wykonywania. – odlund

+6

Kompilator powinien był Cię ostrzec przed użyciem surowego typu 'Class' zamiast sparametryzowanego typu' Class <> ', co byłoby twoją wskazówką, że coś jest nie tak z tą deklaracją. – Alex

Odpowiedz

16

musisz określić parametru type Class:

Class<String> stringclass = (Class<String>) thetype.getClass(); 

lub

Class<? extends String> stringclass = thetype.getClass(); 

java.lang.Class.cast(Object obj) rzuca obiekt do klasy lub interfejsu reprezentowanego przez ten obiekt klasy.

Bez podania typu nie mówisz kompilatorowi, która klasa lub interfejs jest reprezentowany przez instancję Class instancji stringclass.

Po wywołaniu String.class, obiekt Class jest niejawnie parametryzowany z typem String.

11

W Java Language Specification stany

Typ C.class gdzie C jest nazwą klasy, interfejs lub typu tablicy (§4.3) jest Class<C>.

Więc rodzaj ekspresji

String.class 

jest Class<String>. Class to klasa ogólna, w której metoda cast używa zmiennej typu ogólnego w swoim typie zwracanym. Więc wynik

String.class.cast(bar); 

jest wyrazem typu T, gdzie T został związany String w tej inwokacji.

Typ zwrotu Object#getClass() to Class<? extends T>, gdzie T jest wymazanym typem wyrażenia, na które się on wywołuje.

W tym przypadku, to jest

Class<? extends String> 

Jednak przypisujemy go do surowca odniesienia.

Class stringclass = thetype.getClass(); 

Od zmiennej stringclass jest raw, any uses of its methods that depend on the generic type variable are erased.

Więc Class#cast(Object) teraz ma typ powrót Object który nie jest przypisywany do zmiennej String.

Gdybyś zrobił

Class<? extends String> stringclass = thetype.getClass(); 

byłbyś w porządku.

Powiązane problemy