2011-11-30 3 views
22

È possibile parametrizzare genericamente un metodo accettando EITHER ClassA OR InterfaceB?Generico OR invece di AND <T estende Numero | CharSequence>

Non compilato a causa di | Pseudocodice

public <T extends Number | CharSequence> void orDoer(T someData){ // ... } 

cioè invece di scrivere più firme del metodo, vorrei questo un metodo di accettare un numero o CharSequence come argomento

dovrebbe passare con un numero o argomento CharSequence

+4

Che cosa fareste dentro quel metodo che non può essere fatto con due metodi separati che accettano 'number' o' CharSequence' rispettivamente, e poi delegare ad una terza, metodo privato per fare il lavoro? –

+1

Sono d'accordo che i guadagni sono inconsistenti se ho a che fare con due tipi, ma sembrerebbe un modo abbastanza conciso per delegare più tipi di parametri (che non condividono un supertipo utilizzabile) – Cel

+1

Dovresti controllare [Ceylon] (http: // ceylon-lang.org/documentation/1.1/introduction/) Tipi di sindacati. ;) – Anonsage

risposta

16

Se si davvero si desidera farlo, è necessario avvolgere le classi accettate all'interno di una classe personalizzata di yo proprio. Nel tuo esempio caso, probabilmente qualcosa come:

public class OrDoerElement { 
    private final Number numberValue; 
    private final CharSequence charSequenceValue; 

    private OrDoerElement(Number number, CharSequence charSequence) { 
     this.numberValue = number; 
     this.charSequenceValue = charSequence; 
    } 

    public static OrDoerElement fromCharSequence(CharSequence value) { 
     return new OrDoerElement(null, value); 
    } 

    public static OrDoerElement fromNumber(Number value) { 
     return new OrDoerElement(value, null); 
    } 
} 

e il metodo di orDoer diventa:

public void orDoer(OrDoerElement someData) { .... } 

Poi si può costruire uno di quelli e di utilizzare nel metodo utilizzando:

orDoer(OrDoerElement.fromCharSequence("a string of chars")); 
orDoer(OrDoerElement.fromNumber(new Integer(6))); 

Ma onestamente, sembra un po 'troppo complesso e troppo lavoro solo per essere in grado di chiamare un metodo con diversi tipi di parametri. Sei sicuro di non poter ottenere lo stesso usando due metodi e un terzo metodo per la logica comune?

+0

Grazie per la risposta! Mi rendo conto ora che non ho spiegato correttamente il mio caso d'uso - stavo cercando qualcosa di molto simile a "T estende ClassA | InterfaceB' perché volevo che il chiamante del mio metodo fosse in grado di passare nel loro tipo as-is (Integer o String etc direttamente). Ovvero, per fornire un metodo 'store (T data)', che accetterebbe tutti i tipi di tipi che hanno la caratteristica di essere completamente ricostruibile da .toString() e una istanziazione standard a parametro singolo (Number, CharSequence, Date e molti tipi più persistenti). – Cel

+0

ovvero un altro modo in cui avrei potuto porre la domanda è perché non esiste un tipo condiviso - prima di Object - for Number, CharSequence e altri tipi nativi, che li caratterizzerebbe come quelli Uniconstructables o come si vorrebbe chiamarli .. (spero che sia ha senso) – Cel

+0

Sì, capisco, questo tipo di classe super-super sarebbe davvero utile in alcuni casi – Guillaume

1

L'uso di una classe astratta anonima è un'opzione per te? Quando ho bisogno di digitare parametri sicuri o tipi restituiti, utilizzo alcune varianti del codice riportato di seguito. Detto questo, sono d'accordo con gli altri commenti qui, e sono curioso di sapere quali benefici si traggono davvero quando si impone un tipo di sicurezza per un gruppo di oggetti che non hanno molto in comune.

public abstract class Doer<T> { 

    public void do(T obj) { 
    // do some stuff. 
    } 

} 

// calling method 

new Doer<Number>(){}.do(new Integer(5)); 
+1

Grazie, per favore vedi i chiarimenti sotto il post di Guillaume. – Cel