Esempio di problema causato dalla fusione dell'oggetto [] su E []

1

Ho sentito qua e là che gli array contengono dati di runtime sul loro tipo, rendendoti impossibile istanziare un E[] ( E è un parametro di tipo generico, ad esempio in una classe Foo<E> ), e che mentre puoi ottenere lo stesso effetto facendo (E[]) new Object[n] , è cattivo, motivo per cui il compilatore solleva un avvertimento. Ho problemi a pensare a cosa esattamente potrebbe andare storto (le ultime parole famose), quindi qualcuno potrebbe dare un esempio di come un programma potrebbe diventare difettoso a causa dell'istanziamento di Object[] s e del loro cast in E[] ?

    
posta Phoenix 15.09.2016 - 03:10
fonte

2 risposte

3

Se l'array viene utilizzato solo all'interno della classe e il fatto che il tipo della variabile come E[] non viene mai esposto all'esterno della classe (ad esempio, restituito in un metodo, oppure è un campo pubblico o protetto, ecc. .), quindi non vi è alcun problema dato che all'interno della classe E viene cancellato.

Tuttavia, se esporti il fatto del tipo della variabile dell'array come E[] all'esterno della classe, allora può entrare in un contesto in cui hanno un tipo concreto per il tuo E , e giustamente credi che cosa stanno ottenendo questo tipo di array e genereranno un ClassCastException senza alcun avviso in quel codice esterno. L'esempio più semplice è un metodo che restituisce semplicemente l'array come E[] , e viene chiamato da un codice esterno che ha un tipo concreto come parametro type; un ClassCastException viene generato dal codice esterno senza alcun avviso in quel codice esterno o nel metodo che restituisce l'array:

public class Foo<E> {

    private E[] myArray = (E[])new Object[42];

    public E[] getArray() {
        return myArray;
    }

}

// some outside code:
Foo<String> foo = new Foo<String>();
String[] stringArray = foo.getArray(); // ClassCastException
    
risposta data 15.09.2016 - 06:14
fonte
0

Potresti, ovviamente, dichiarare l'array come Object [] e scrivere un accessor privato come

Object[] elements = ...;

@SuppressWarnings("unchecked")
private E getElement(int index)
{
    return (E)elements[index];
}

In questo modo, non hai un campo con la dichiarazione che sta a te e ad ogni altro lettore del tuo codice, e confinare il cast in un singolo luogo. Il cast è un no-op, btw., Perché non c'è modo per il compilatore di fare un vero cast reale a un tipo non reificato.

Questo è in effetti esattamente ciò che accade all'interno di molte implementazioni di raccolte ben scritte.

Il cast per E [] può avere vantaggi prestazionali per una vera raccolta reale, quindi è il modo di andare in quei pochi posti in cui scrivi codice che influenza molto altro codice, dal punto di vista delle prestazioni.

Utilizza i commenti, perché le cose eccezionali sono l'unica area in cui possono essere preziose. Trattenere il campo di applicazione. Pensa tre volte a quello che stai facendo in ogni passaggio, e dovresti stare bene:)

Nel caso in cui la performance NON sia di primaria importanza, però, usa semplicemente l'accessor

risposta data 15.09.2016 - 08:01
fonte

Leggi altre domande sui tag