Domanda

Ho difficoltà a lanciare un elenco di frutta nella sottoclasse di frutta contenuta nell'elenco.

public class Response {
    private List<Fruit> mFruitList;
    public List<Fruit> getFruitList() {
        return mFruitList;
    }
} 

public class Fruit {
}

public class Orange extends Fruit {
}

List<Fruit> oranges = response.getFruitList();

Come faccio a lanciare arance in modo che sia un elenco di Class Orange? È un cattivo modello di design? Fondamentalmente ricevo una risposta JSON da un server che è un elenco di frutta. Per ogni chiamata specifica al servizio Web, so quale sottoclasse di frutta riceverò e quindi devo lanciare tale elenco in modo appropriato.

È stato utile?

Soluzione

Se conosci per ogni chiamata specifica, quale sottoclasse di frutta otterrai, dovresti usare generici invece di fusione.

public class Response<T extends Fruit> {
    private List<T> mFruitList;
    public List<T> getFruitList() {
        return mFruitList;
    }
} 

Response<Orange> response = // create
List<Orange> oranges = response.getFruitList();

EDIT: per modelli intendevo tipi generici. Scusa, avevo troppo C ++ al giorno d'oggi

Altri suggerimenti

L'intera idea dietro tipografi è quella di essere in grado di dire al compilatore: "Ehi, ne so di più di te". Nel tuo codice, il compilatore non può correre in modo sicuro il List<Fruit> a List<Orange> Perché non può sapere cosa conterrà l'elenco in fase di esecuzione.

Se tu sei assolutamente certo che l'elenco sarà solo Orange istanze e rende il tuo codice più gestibile per abbattere, provarlo.

List<Orange> oranges = (List<Orange>) response.getFruitList();

Il compilatore ti darà un avvertimento, ovviamente, dal momento che stai facendo qualcosa che pensa che non dovresti fare. E sappi solo che il JVM potrebbe avere l'ultima risata lanciando un CastClassException Se avevi torto!

Pensa ai generici come un gate per quali tipi di oggetti può contenere un elenco. A causa di questa eredità e casting non funzionerà come ci si aspetterebbe. Nell'esempio che hai dato potrebbe mettere sia arance che mele nel tuo List<Fruit>. Se l'elenco ha sia mele che arance come puoi lanciarlo a un List<Orange>.

Se hai bisogno di un List<Orange> allora perché anche preoccuparsi del List<Fruit>. Se lo stai esplicitamente lanciando comunque e sai esattamente cosa contiene è probabilmente un'astrazione inutile.

Se stai lavorando con un'API non puoi cambiare, ma sai esattamente cosa contiene, dovresti passare a un controllo di un esempio solo per assicurarti che e esplicitario lanci ciascuno Fruit istanza a Orange Quando hai bisogno di Orange API.

Dovresti lanciare elenco e testare se ogni elemento lo è instanceof Orange, e dopo il test lanciato in arance. Questa è la "migliore pratice".

Dato

List<Fruit> getFruits() {...}

Non puoi tipografi

List<Orange> oranges = (List<Orange>) getFruits();

A causa della cancellazione del tipo, in fase di esecuzione il tipo di getfruits è solo un elenco. Il compilatore non ti permetterà nemmeno di fare il downcast (ero in dubbio, quindi ho provato in Eclipse prima di rispondere).

Potresti dire al compilatore che la tua lista conterrà una sottoclasse di frutta, in quel caso, devi usare un jolly sul tuo metodo:

List<? extends Fruit> getFruits() {...}

Quindi il cast diventa possibile, ma con un avviso di sicurezza del tipo:

@SuppressWarnings("unchecked")
List<Orange> oranges = (List<Orange>) getFruits();

Dato che il tipo di runtime di getfruits è Elenca, puoi semplicemente scartare le informazioni del tipo generico e utilizzare un assiggio non sicuro:

@SuppressWarnings("unchecked")    
List<Orange> oranges = (List) getFruits();

Forse un modo più elegante in quanto afferma chiaramente la tua intenzione, anche se richiedere più risorse di sistema sarebbe:

List<Orange> oranges = Arrays.asList((Orange[])getFruits().toArray())

Gli array in Java conservano le loro informazioni di tipo in fase di esecuzione, quindi il cast è valido e "sicuro" dalla prospettiva del compilatore, ma può lanciare un'eccezione di runtime se si passa alcune mele nel cestino della frutta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top