2013-08-23 15 views
8

ho un'interfaccia che assicura oggetti possono effettuare copie di sé:sottoclassi che ereditano interfacce generiche

public interface Duplicable<T extends Duplicable<T>> { 
    public T duplicate(); 
} 

ora ho

class X implements Duplicable<X> 

ma anche un Y classe che estende X.

Questo non è un problema, fino a quando ho bisogno di un altro classe generica:

public class DoStuffWithDuplicable<T extends Duplicable<T>> 

non posso usare una versione generica di DoStuffWithDuplicable usando Y, dal momento che non implementa Duplicable<Y> ma Duplicable<X> dato che eredita da X.

Così ho provato

public class DoStuffWithDuplicable<T extends Duplicable<? super T>> 

.. ma questo mezzo in seguito introducendo un cast pericoloso

(T) obj.duplicate() 

nel corpo del codice. Anche i parametri di classe sono più contorti e l'uso della classe più difficile da capire. Qualche idea su come aggirare questo problema?

+0

Puoi riformulare questo: "Non è possibile utilizzare una versione generica del DoStuffWithDuplicable usando Y, dal momento che lo fa non implementare Duplicable ma Duplicable poiché lo eredita da X. " ? – tbsalling

+0

scusa, problema di formattazione – phil

+1

Come nota, questo è esattamente il motivo per cui alcuni scienziati informatici affermano che tutte le classi dovrebbero essere "abstract" o "final". Incontrerai anche problemi con 'equals'; puoi forse fare il refactoring per eliminare l'esistenza di un 'X' istantaneo? – chrylis

risposta

1

Forse non ho capito bene la tua domanda, ma ci provo.

Prima di tutto, perché hai un'interfaccia che si estende così?

Che cosa si può provare è questo:

public interface Duplicable<T> { 
    public T duplicate(); 
} 

Poi, quando si utilizza un'altra classe in cui si desidera che il parametro generico per essere duplicabile, lo si fa in questo modo:

public class X<T extends Duplicable<T>> { 
    code... 
} 

Ora, quando si ereditato da X, qualsiasi componente generico nelle sottoclassi dovrà essere duplicabile.

+1

Penso che il "perché" è abbastanza chiaro: OP vuole vincolare 'T' allo stesso tipo della classe che lo implementa. Il tuo modo consente, ad esempio, 'Intero' di implementare' Duplicabile '. –

+0

@MarkoTopolnik: 1) Ma il vincolo dell'OP non lo vincola. Non è possibile vincolarlo. 2) E il vincolo dell'OP non ha comunque alcuno scopo di sicurezza del tipo. L'interfaccia è sicura come è. – newacct

+0

Il limite '>' vincola 'T' allo stesso modo di' Enum' limita il suo parametro type: 'Enum >'. 'E' deve essere la classe enum stessa. –

1

Non è possibile farlo in Java.

Si supponga di chiamare obj.duplicate() su un oggetto di tipo Y. Quindi il sistema di tipi può solo garantire che restituirà un oggetto di tipo X, poiché Y implements Duplicato <X>.

Ma è sufficiente creare un DoStuffWithDuplicable <X> e passare ad esso oggetti Y.

DoStuffWithDuplicable<X> blub = new DoStuffWithDuplicable<X>(); 
    Y y = (Y) blub.doStuff(new Y()); 

Per i valori restituiti, il client della libreria può semplicemente utilizzare i cast sicuri, poiché probabilmente conosce i tipi concreti.

Un'altra opzione sarebbe quella di utilizzare calchi non sicuri nella biblioteca e controllare i tipi manualmente:

class DoStuffWithDuplicable<T extends Duplicable<? super T>> { 
    T doStuff(T obj) { 
     @SuppressWarnings("unchecked") 
     T t = (T) obj.duplicate(); 
     if (!t.getClass().equals(obj.getClass())) 
      throw new ClassCastException("..."); 
     return t; 
    } 
} 
Problemi correlati