2011-03-18 12 views
22

Mam klasę abstrakcyjną, która ma metodę ogólną i chcę nadpisać metodę ogólną poprzez podstawienie określonych typów dla parametru ogólnego. Tak więc w pseudokodzie mam:Podstawowe reguły dziedziczenia i zastępowania metod Java

public abstract class GetAndParse { 
    public SomeClass var; 

    public abstract <T extends AnotherClass> void getAndParse(T... args); 
} 

public class Implementor extends GetAndParse { 
    // some field declarations 

    // some method declarations 

    @Override 
    public <SpecificClass> void getAndParse(SpecificClass... args) { 
    // method body making use of args 
    } 
} 

Ale z jakiegoś powodu nie wolno mi tego robić? Czy popełniam jakiś błąd składniowy, czy też jest to dziedziczenie i nadpisywanie niedozwolone? W szczególności dostaję błąd o numerze @Override, ponieważ IDE Eclipse nieustannie przypomina mi o implementacji getAndParse.

Oto, jak chcę, aby powyższy kod zadziałał. Gdzieś indziej w moim kodzie istnieje metoda, która oczekuje wystąpień obiektów, które implementują GetAndParse, co konkretnie oznacza, że ​​mają one metodę getAndParse, której mogę użyć. Kiedy wywołuję getAndParse w tej instancji, kompilator sprawdza, czy użyłem określonych instancji T we właściwy sposób, więc w szczególności T powinien przedłużyć AnotherClass i powinien być SpecificClass.

+0

Pseudo-kod zbyt abstrakcyjny, potrzebuję więcej informacji – irreputable

+0

Używanie 'public abstract void getAndParse (Args ... args);' nie ma sensu. Do czego służy parametr typu? W jaki sposób kompilator określa jego rzeczywistą wartość i gdzie powinien go używać? – maaartinus

+0

Czy możesz podać nam pełny przykład, który jest w rzeczywistości możliwy do skompilowania (poza problematycznym błędem) i powoduje zgłoszenie błędu, o którym wspomniałeś? –

Odpowiedz

23

Mamy tutaj dwie różne metody z indywidualnymi parametrami każdego typu.

public abstract <T extends AnotherClass> void getAndParse(Args... args); 

Jest to sposób z parametrem typu nazwie T i jest ograniczona AnotherClass, to znaczy każdego podtypu AnotherClass pozostawia się jako parametr typu.

public <SpecificClass> void getAndParse(Args... args) 

Jest to sposób z parametrem typu nazwie SpecificClass, ograniczoną Object (to znaczy każdy typ jest dozwolony jako parametr typu). Czy naprawdę tego chcesz?

Czy parametr typu jest używany wewnątrz Args? Myślę, że problem byłby tam.


Edit:

Znaczenie

public abstract <T extends AnotherClass> void getAndParse(T... args); 

jest to, że rozmówca metody może zdecydować, z którymi typ parametru chce wywołać metodę, tak długo, jak to jest jakiś podtyp AnotherClass. Oznacza to, że w efekcie metodę można wywołać z dowolnymi obiektami typu AnotherClass.

Ponieważ wywołujący może decydować o parametrze typu, nie można w podklasie zawęzić parametru do SpecificClass - nie byłoby to implementacją metody, ale inną metodą o tej samej nazwie (przeciążenie).

Może chcesz coś takiego:

public abstract class GetAndParse<T extends AnotherClass> { 
    public SomeClass var; 

    public abstract void getAndParse(T... args); 
} 

public class Implementor extends GetAndParse<SpecificClass> { 
    // some field declarations 

    // some method declarations 

    @Override 
    public void getAndParse(SpecificClass... args) { 
    // method body making use of args 
    } 
} 

Teraz metoda getAndParse implementuje metodę klasy nadrzędnej.

+3

Nie chcę parametru typu. Chcę, aby kompilator sprawdził i upewnij się, że 'SpecificClass' jest rozszerzeniem' AnotherClass'. – davidk01

1

Nie, to nie jest prawidłowe. Co by się stało, gdyby ktoś o numerze referencyjnym GetAndParse nazwał go inną klasą rozszerzającą AnotherClass?

+0

Nie rozumiem, dlaczego to jest problem.Mam implementor, który rozszerza 'GetAndParse' i naprawia typ' T' na 'SpecficClass', który sprawdza kompilator, aby upewnić się, że rozszerza' AnotherClass', a następnie w moim kodzie, gdy mam instancję 'Implementor' i wywołuję' getAndParse' z typem, który nie pasuje do 'SpecificClass', powinienem otrzymać błąd. – davidk01

+0

@ davidk01: Umowa dostarczona przez GetAndParse mówi, że każdy, kto ją wdraża, musi to zrobić dla dowolnego typu rozszerzenia usługi AnotherClass. Biorąc pod uwagę 'GetAndParse foo = new Implementor();' musisz móc wywołać 'foo.getAndParse' dla dowolnego rozszerzenia AnotherClass - Jeśli kompilator tego nie wymusił, możesz równie dobrze użyć Object, celem generycznych jest zapewnij bezpieczeństwo typu kompilacji – Erik

1

To staje się bzdurą, gdy ktoś ma odnośnik do typu GetAndParse i próbuje wywołać metodę getAndParse. Jeśli Cat i Dog rozszerzają AnotherClass. Oczekuję, że będę mógł wywołać GetAndParse # getAndParse z kotem lub psem. Ale implementacja próbowała go ograniczyć i sprawić, by był mniej kompatybilny!

+0

Z tego powodu nie możesz tego zrobić, przepraszam, jeśli oprawiam go w sposób, który Ci się nie podoba. Generics czasu kompilacji nie są w stanie wymusić tego dla ciebie. W jaki sposób kompilator ma wiedzieć, jaka podklasa będzie w nim występować? Jest całkowicie możliwe, że narzędzie jest zwracane przez interfejs fabryczny i pochodzi z innej biblioteki, której nie kompilujesz! Zawężenie parametru typu nie może być sprawdzane pod kątem bezpieczeństwa podczas kompilacji. – Affe

8

Widzisz ten problem z powodu koncepcji o nazwie "Erasure" w Java Generics. Java używa "usuwania" w celu zapewnienia kompatybilności wstecznej. tj. kod Java, który nie używa generycznych.

Erasure Procedura:
Kompilator będzie najpierw zrobić sprawdzanie typu, a następnie usunie (erase) wszystkie parametry typu jak najwięcej, a także wstawić rzutowania, gdzie zawsze jest to konieczne.

przykład:

public abstract <T extends AnotherClass> void getAndParse(T paramAnotherClass); 

staną

public abstract void getAndParse(AnotherClass paramAnotherClass); 

w klasie "Implementor.java"

Kod

public <SpecificClass> void getAndParse(T paramAnotherClass) 

staną

kompilator zobaczy, że nie zaimplementowano poprawnie metody abstrakcji. Występuje niedopasowanie typu między metodą abstrakcyjną a zaimplementowaną metodą. Właśnie dlatego widzisz błąd.

Więcej informacji można znaleźć tutaj. http://today.java.net/pub/a/today/2003/12/02/explorations.html

1

Nie można przesłanianie do konkretnego typu T, ponieważ nie jest w rzeczywistości (na poziomie kodu bajtowego, jeśli chcesz) tylko jedna metoda getAndParse ponieważ typu skasowaniem (zobacz inne odpowiedzi):

public abstract void getAndParse(AnotherClass... args); // (1) 

Dla każdego typ T, stosowana jest ta sama metoda.

Można przeciążenie to (chyba):

ale nie będzie to inna metoda z (1) mrówka będzie nie być nazywany kodem Generic:

T x = whatever; 
    object.getAndParse(x); // Calls (1) even if T is derived from SpecificClass 
Powiązane problemy