2013-08-22 12 views
8

Sono di fronte al problema descritto in this question ma vorrei trovare una soluzione (se possibile) senza tutti i cast e le annotazioni @SuppressWarning.Metodo ereditato restituito tipo di riferimento

Una soluzione migliore sarebbe quella che si basa sul fatto riferimento a uno a:

  • rimozione @SuppressWarning
  • rimozione calchi

soluzioni presentate qui sarà classificato con 2 punti in base al criteri. Bounty va in soluzione con la maggior parte dei punti o il "più elegante" se ce n'è più di uno con 2 punti.

+0

aggiungerà di taglie in 2 giorni a causa del meccanismo SO offrendo taglie. Sentiti libero di postare la tua risposta ora, però. – pnt

+0

correlati: [C'è un modo per fare riferimento al tipo corrente con una variabile di tipo?] (Http://stackoverflow.com/questions/7354740/is-there-a-way-to-refer-to-the-current -type-with-a-type-variable) –

risposta

9

No cast, non @SuppressWarning, solo poche righe:

public abstract class SuperClass<T extends SuperClass<T>> { 
    protected T that; 
    public T chain() { 
     return that; 
    } 
} 

public class SubClass1 extends SuperClass<SubClass1> { 
    public SubClass1() { 
     that = this; 
    } 
} 

public class SubClass2 extends SuperClass<SubClass2> { 
    public SubClass2() { 
     that = this; 
    } 
} 
+1

Questo è stato scelto come risposta migliore perché evita completamente le trasmissioni, non ha @SuppresWarnings ed è, secondo me, il più elegante in quanto evita anche l'override del metodo (il riferimento che devi "sovrascrivere" sembra più pulito e richiede meno codice, ma è anche nascosto all'utente che si ignora qualcosa). Otterrai la taglia in 23 ore. – pnt

+0

@pnt Questa è fondamentalmente la stessa soluzione della risposta accettata nella domanda di riferimento. Perché non ti è piaciuto e lo accetti qui? –

+1

@FrancoisBourgeois In realtà, questa non è la stessa soluzione. Nell'altra soluzione, con 'return (T) this;' nella classe abstract, il compilatore non può sapere in fase di compilazione se il cast è sicuro (anche se può essere, solo lo sviluppatore sa), quindi il bisogno di l'annotazione @SuppressWarning. Nella mia soluzione, non è necessario eseguire il cast poiché 'that' è impostato direttamente all'interno della sottoclasse. E questa * soluzione senza cast * è esattamente ciò che è stato chiesto qui. – sp00m

1

Una soluzione è sovrascrivere il metodo nella classe figlio e modificare il tipo restituito in uno più specifico, ad es. il tipo di bambino. Questo richiede il casting. Invece di utilizzare la tipica (Child) cast, utilizzare il metodo Class#cast(Object)

public class Parent { 
    public Parent example() { 
     System.out.println(this.getClass().getCanonicalName()); 
     return this; 
    } 
} 

public class Child extends Parent { 
    public Child example() { 
     return Child.class.cast(super.example()); 
    } 

    public Child method() { 
     return this; 
    } 
} 

Il cast è nascosto all'interno del metodo standard. Dalla sorgente di Class.

public T cast(Object obj) { 
    if (obj != null && !isInstance(obj)) 
     throw new ClassCastException(cannotCastMsg(obj)); 
    return (T) obj; 
} 
+0

Non proprio una soluzione perché non rimuove i cast (solo li avvolge e li nasconde) e non risolve il problema originale nella domanda di riferimento. Sì, ovviamente puoi sovrascrivere il metodo per restituire un tipo più specifico, ma l'intero punto è riutilizzarlo e non doverlo sovrascrivere in ogni figlio. – pnt

+0

@pnt Il problema è stato _Io voglio implementarlo senza l'utilizzo di interfacce aggiuntive e metodi aggiuntivi, e di usarlo senza cast di classe, argomenti ausiliari e così via. La cosa è che non puoi. Le soluzioni proposte hanno tutti o metodi aggiuntivi e/o argomenti extra. O si ignora il metodo in questione o si introduce un altro metodo nel padre e si sovrascrive quello. Nella soluzione Generics, è inoltre necessario introdurre un parametro di tipo. –

5

Un approccio è quello di definire un metodo astratto getThis() in Parent classe, e fare tutte le classi Child sostituirla, restituendo il riferimento this. Questo è un modo per recuperare il tipo di oggetto this in una gerarchia di classi.

Il codice sarebbe simile a questa:

abstract class Parent<T extends Parent<T>> { 

    protected abstract T getThis(); 

    public T example() { 
     System.out.println(this.getClass().getCanonicalName()); 
     return getThis();   
    } 
} 

class ChildA extends Parent<ChildA> { 

    @Override 
    protected ChildA getThis() { 
     return this; 
    } 

    public ChildA childAMethod() { 
     System.out.println(this.getClass().getCanonicalName()); 
     return this; 
    } 
} 

class ChildB extends Parent<ChildB> { 

    @Override 
    protected ChildB getThis() { 
     return this; 
    } 

    public ChildB childBMethod() { 
     return this; 
    } 
} 


public class Main { 

    public static void main(String[] args) throws NoSuchMethodException { 
     ChildA childA = new ChildA(); 
     ChildB childB = new ChildB(); 

     childA.example().childAMethod().example(); 
     childB.example().childBMethod().example(); 
    } 
} 

Secondo il requisito, non v'è alcuna Casting e nessun @SuppressWarnings. Ho imparato questo trucco qualche giorno fa da Angelika Langer - Java Generics FAQs.

Riferimento:

+1

Si potrebbe voler rendere la dichiarazione 'Parent >'. Altrimenti si potrebbe fare "estende Parent " e il metodo di concatenamento terminerebbe con 'String getThis()'. –

+0

@SotiriosDelimanolis. Ah! Destra. Grazie :) –

Problemi correlati