2016-07-01 17 views
8

Mam prosty program tak:Java rodzajowych - rozszerzenie klasy rodzajowe z funkcją rodzajowy

package test; 

public class TestGenericsInheritance { 

    public static void main(String[] args) {} 

    public static abstract class A<Q>{ 

     public void foo2(Q obj){} 
     public abstract <T> void foo(T obj); 
    } 

    public static class C extends A<Object>{ 

     @Override 
     public <T> void foo(T obj) {} 
    } 

    public static class B extends A{ 

     @Override 
     public <T> void foo(T obj) {} 
    } 
} 

Jak widać Czyni absolutnie nic. Kompilacja tego programu plików na Java 1.6 i 1.7 z następującym błędem:

/D:/Projects/.../test/TestGenericsInheritance.java:[24,19] test.TestGenericsInheritance.B is not abstract and do es not override abstract method foo(java.lang.Object) in test.TestGenericsInheritance.A /D:/Projects/.../test/TestGenericsInheritance.java:[27,25] name clash: foo(T) in test.TestGenericsInheritance .B and foo(T) in test.TestGenericsInheritance.A have the same erasure, yet neither overrides the other /D:/Projects/.../test/TestGenericsInheritance.java:[26,9] method does not override or implement a method from a supertype

Klasy C i B są semantycznie identyczne, jednak klasa B nie rozpoznaje metody foo jako wdrożenie # foo. Aby uczynić ten kod zgodny trzeba zaimplementować metoda A # foo w klasie B z następującym podpisem:

public void foo(Object obj) 

Moje pytanie brzmi, dlaczego mój program nie kompiluje? Typy ogólne Q i T są całkowicie niezależne, więc dlaczego mogę zaimplementować funkcję ogólną A # foo tylko wtedy, gdy jawnie określę rodzajowy typ Q dla odziedziczonej klasy A?

Dzięki

+0

Jestem w stanie wydać repro ". Co więcej, posiadanie nietypowej metody i ogólnej metody powoduje jednocześnie błąd usuwania tego samego typu. – 4castle

+0

Eclipse sugeruje dodanie: '' '@Override public void foo (Object obj) {}' '' '' 'B''', które faktycznie powoduje jego kompilację. (1.8) –

+0

@ 4castle Twoja edycja spowodowała, że ​​komunikaty o błędach są mylące, ponieważ wspominają o usuniętej nazwie pliku źródłowego. –

Odpowiedz

6

B rozszerza typ surowej A. Ponieważ używasz typu surowego, wszystkie ogólne informacje są wymazywane, a nie tylko zmienna typu, której nie udało się określić (patrz Section 4.6 of the Java Language Specification). Oznacza to, że A ma metodę void foo(Object obj), podczas gdy A<SomeType> ma metodę <T> void foo(T obj).

Jeśli nadpisujesz metodę, musi ona mieć ten sam podpis (opcjonalnie po usunięciu typu zastąpionej metody) - co ciekawe, metoda przesłaniania może mieć inny, bardziej szczegółowy typ zwracany. Sygnatury twoich dwóch metod są różne (musisz wymazać typ w metodzie przesłaniania), a zatem Twój przykład nie zostanie skompilowany.

Powód usunięcia tekstu został zaimplementowany bez zmian, jest zgodny wstecz. Pomysł polegał na tym, że nowy kod używałby tylko generycznych i tylko stary kod używałby typów surowych. Tak więc celem nie było uczynienie typów surowych najwygodniejszymi (ponieważ nowy kod nie powinien ich używać), ale aby typy surowe były najbardziej kompatybilne.

Weźmy na przykład klasę ArrayList, która została wprowadzona w języku Java 2 (dużo wcześniej niż w przypadku generycznych). Miał metodę public Object[] toArray(Object[] a). W języku Java wprowadzono 5 generics, a sygnatura tej metody mogła zostać zmieniona na public <T> T[] toArray(T[] a) (gdzie T nie jest typem elementu) bez trudności: ze względu na sposób usuwania typu jest zaimplementowany, dla starego kodu, który użył (lub podzielił) niż ArrayList<SomeType> podpis metody pozostał taki sam.

+0

Nadal go nie rozumiem. Gdzie jest "usuwane wszystkie ogólne informacje" pojawia się w specyfikacji? – 4castle

+1

Mówi: "Wymazanie typów również odwzorowuje podpis (§ 8.4.2) konstruktora lub metody na sygnaturę, która nie ma sparametryzowanych typów lub zmiennych typu." Nie wspominając o żadnych dodatkowych warunkach. – Hoopje

+0

@Hoopje Dziękuję za wyjaśnienia. Rozumiem, co jest przyczyną mojego problemu.Jednak nie widzę sensu w usuwaniu wszystkich rodzajów ogólnych w takim przypadku. Rozumiem, że parametr typu powinien zostać usunięty. Ale po co kasować parametr metody, jeśli jest on niezależny od parametru typu? Czy możesz podać przypadek, w którym takie usunięcie jest konieczne? – MAREK

Powiązane problemy