2015-02-27 14 views
13

Angelica Langer mówi w swoim FAQ na temat leków generycznych (patrz Technicalities.FAQ822):Przesłanianie metody rodzajowe przez rodzajowe jeden w Javie

Jeśli te metody mają parametry typu o różnych granicach, potem nie zastępują, ponieważ metody mają podpisy, które nie są równoważne przez nadpisanie. Pamiętaj, że ograniczenia parametrów typu są częścią sygnatury metody ogólnej.

Przykład (ogólnych metod podtypu przeciążenia rodzajowy supertypem metod, nie zaleca się)

class Super { 
    public <T> void set(T arg) { ... } 
    public <T> T get() { ... } 
} 
class Sub extends Super { 
    public <S extends Number > void set(S arg) { ... } // overloads 
    public <S extends Number > S get() { ... }   // overloads 
} 

nie rozumieć, dlaczego sposób get jest przeciążone w klasie Sub. Z tego, co wiem, powinien to być błąd czasu kompilacji, ponieważ get ma tę samą sygnaturę zarówno w Sub jak i Super (typ powrotu nie jest częścią tego).

Co mylą mnie jeszcze bardziej to, że IDE używam do testowania kodu (IntelliJ IDEA 14.0.3) podkreśla get w Sub jako błąd kompilacji z Następna wiadomość:

„get () 'in' Sub 'zderza się z' get() 'w' Super '; obie metody mają to samo usunięcie, ale żadna nie zastępuje drugiej.

Ale po uruchomieniu programu kompiluje się i wykonuje bez problemów. Przypuszczam, że jest jakiś błąd w IntelliJ, gdy analizuje kod i co jest poprawne, co Angelica mówi w swoim FAQ. Ale nie mogę tego zrozumieć.

+2

W środowisku Eclipse można ustawić wbudowany kompilator jako bardziej rygorystyczny i traktować określone warunki jako błędy (np. Przypisanie do siebie lub uzyskanie dostępu do metody statycznej za pośrednictwem instancji). Przypuszczam, że to samo można zrobić w IDEA. – biziclop

+0

Problem polega na tym, że parametr typu zastąpionej metody nie ma takich samych ograniczeń jak parametr typu metody z klasy super. –

+6

Jak wspomniano we wpisie, który cytujesz, _ograniczenia parametrów typu są częścią sygnatury metody ogólnej. Tak więc ' T get()' i ' S get()' mają różne podpisy. Zderzenie nazw jest nadal złe, więc w ten sposób plakat mówi, że jest _nie zalecany_ –

Odpowiedz

0

Myślę, że usunięcie public <S extends Number> S get() nie jest takie samo lub covariant z public <T> T get().

To kompiluje i działa:

class B { 
    public <T> T get() { 
     return null; 
    } 

} 

class A extends B { 
    @Override 
    public <S> S get() { 
     return null; 
    } 

nie:

class B { 
     public <T> T get() { 
      return null; 
     } 

    } 

    class A extends B { 
     @Override 
     public <S extends Number> S get() { 
      return null; 
     } 
+0

To prawda. Pierwszy kod kompiluje się i uruchamia, a drugi nie, ponieważ używasz adnotacji '@ Override' w' get'. Wiem dla najczęściej zadawanych pytań Angeliki Langer, że jest przeciążone, a nie przesłonięte. Czego nie rozumiem, to _dhy_. – Bleyder

+0

@Bleyder Ponieważ 'S' i' T' są parametrami wejściowymi. – biziclop

+0

@biziclop 'S' i' T' są parametrami wejściowymi w _both_ examples. Jednak w drugim jest to błąd podczas kompilacji, ponieważ 'B' nie zastępuje metody' get' ... przeciąża! Dlaczego tak jest? W jaki sposób 'B' w drugim przykładzie może przeciążyć i nie przesłonić? – Bleyder

0

Z tego co rozumiem, dlaczego jest to przeciążeniem zamiast przesłanianie dlatego, że kompilator nie widzi go jako ręcznym -równowartość. W odpowiedzi na najczęściej zadawane pytania dotyczące Angeliki Langer omawia się kwestię, dlaczego nadpisywanie metody nie jest zgodne z oczekiwaniami.

http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ051

Podsumowując, metody mają takie same mają te same nazwy i parametry, ale na podstawie ogólnej podtyp jest zdefiniowany jako różne. Nawet z adnotacją przesłaniania kompilator widzi ją jako metodę przeciążenia. Przy stosowaniu generycznych istnieje dodatkowa warstwa dla metody, w której rodzaj ogólny ma zastosowanie jako część metody, która może jednoznacznie ją zdefiniować.

1

Zgodnie z JLS sygnatura metody nie zawiera typu zwracanego, ale tylko nazwę metody i typ jej parametrów. Oznacza to, że podczas kompilowania Super i Sub, błąd kompilacji powinien powrócić, ponieważ Sub.get() ma takie samo usunięcie jak Super.get(), ale nie zastępuje ani nie przeciąża Super.get(). Nie może przesłonić, ponieważ ograniczony typ X rozszerza Number nie jest podtypem typu X i nie może przeciążać, ponieważ typ zwracany nie jest częścią sygnatury metody. Sub.set przeładowuje Super.set w tym przypadku.

Co do tego, dlaczego można go skompilować i uruchomić. Jeśli korzystasz z Java 6, w Javie 6 jest znana bug, która kompiluje Super i Sub. W Javie 7 jest to poprawione i nie będzie dozwolone.

Powiązane problemy