2009-07-07 4 views
5

C'è un modo per dire "questo metodo restituisce this" usando Generics?C'è un modo per dire "il metodo restituisce questo" in Java?

Ovviamente, voglio sovrascrivere questo metodo in sottoclassi, quindi la dichiarazione dovrebbe funzionare bene con @Override.

Ecco un esempio:

class Base { 
    public Base copyTo (Base dest) { 
     ... copy all fields to dest ... 
     return this; 
    } 
} 
class X extends Base { 
    @Override 
    public X copyTo (X dest) { 
     super.copyTo (dest); 
     ... copy all fields to dest ... 
     return this; 
    } 
} 

public <T extends Base> T copyTo (Base dest) non funziona affatto: ricevo "Tipo non corrispondente: Impossibile convertire da Base a T". Se lo forzo con un cast, l'override fallisce.

risposta

4

No, non c'è modo di esprimerlo. Basta dichiarare il metodo per restituire il tipo della classe. Java ha tipi di ritorno covarianti, quindi è possibile sovrascrivere un metodo per restituire comunque un tipo più specifico.

Se si desidera avere un indicatore per questo, è sempre possibile introdurre la propria annotazione, ma non aspettarsi che altri strumenti prendano particolare attenzione.

MODIFICA: la risposta di oxbow_lakes fornisce effettivamente qualcosa che funzionerà nella maggior parte dei casi, ma credo che ci siano dei modi per ingannarlo in modo tale che si sta effettivamente trattando con un tipo diverso. (Dai ricordi della sperimentazione, comunque.) Si noti che questo è simile a come funzionano le enumerazioni Java.

+0

A parte il mio (o meglio, di Martin Odersky) modo; dettagliato sopra –

+0

Sì, anche se ci sono modi per implementare questo tipo di cose senza "Questo" * in realtà * è Questo. –

5

Si può fare qualcosa di molto intelligente (e simile a quello che hanno fatto in Scala con lo 2.8 collection framework). Dichiarare un metodo di interfaccia che dovrebbe restituire "in sé" (Nota:This è un parametro di tipo, non è una parola chiave)

public interface Addable<T, This extends Addable<T, This>> { 
    public This add(T t); 
} 

Ora dichiarano un livello di indirezione - un "modello" di classe

public interface ListTemplate<A, This extends ListTemplate<A, This>> 
    extends Addable<A, This>{ 
} 

public interface List<A> extends ListTemplate<A, List<A>> { 
} 

Poi un'implementazione di List deve restituire un List dal metodo add (ti permetterà di inserire i dettagli impl)

public class ListImpl<A> implements List<A> { 

    public List<A> add(A a) { 
     return ... 
    } 
} 

Allo stesso modo si potrebbe avere un declard SetTemplate e un Set per estendere l'interfaccia Addable - il metodo di add che avrebbe restituito un Set. Splendido, no?

0

utilizzando tipi covarianti dovrebbe essere semplice come:

abstract class Foo<T> { 

    Foo<T> get() { 
     return this.getClass().cast(this); 
    } 
} 

class Bar extends Foo { 

    @Override 
    Bar get() { 
     return (Bar) super.get(); 
    } 
} 
+0

Avresti ricevuto avvisi di tipo non controllato da javac se hai fatto questo –

+0

javac (jdk6) non mi dà alcun avviso. Mi manca qualcosa? – dfa

+0

Devi essere - hai esteso una classe generica (Foo ) ma non hai fornito alcun parametro di tipo (la barra estende Foo) –

Problemi correlati