Domanda

Credo che ci deve essere qualcosa di sottile succedendo qui che io non so. Si consideri il seguente:

public class Foo<T> {
  private T[] a = (T[]) new Object[5];

  public Foo() {
    // Add some elements to a
  }

  public T[] getA() {
    return a;
  }
}

Si supponga che il metodo principale contiene il seguente:

Foo<Double> f = new Foo<Double>();
Double[] d = f.getA();

Si otterrà una CastClassException con il messaggio java.lang.Object non può essere gettato a java.lang.Double.

Qualcuno può dirmi perché? La mia comprensione di ClassCastException è che viene generata quando si tenta di lanciare un oggetto a un tipo che non può essere colato. Cioè, per una sottoclasse di cui non è un caso (per citare la documentazione). per esempio:.

Object o = new Double(3.);
Double d = (Double) o; // Working cast
String s = (String) o; // ClassCastException

E sembra che io possa fare questo. Se a era solo un T invece di un array T[], possiamo ottenere <=> e gettato senza un problema. Perché array rompono questo?

Grazie.

È stato utile?

Soluzione

Foo<Double> f = new Foo<Double>();

Quando si utilizza questa versione della generica classe Foo, poi per la variabile membro a, il compilatore è essenzialmente prendendo questa linea:

private T[] a = (T[]) new Object[5];

e la sua sostituzione con T Double per arrivare a questo:

private Double[] a = (Double[]) new Object[5];

Non puoi lanciare da Object a doppio, da qui il ClassCastException.

Aggiornamento e Chiarimento: In realtà, dopo l'esecuzione del codice di prova, il ClassCastException è più sottile di questo. Ad esempio, questo metodo principale funzionerà benissimo senza alcuna eccezione:

public static void main(String[] args) {
    Foo<Double> f = new Foo<Double>();
    System.out.println(f.getA());
}

Il problema si verifica quando si tenta di assegnare f.getA() ad un riferimento di tipo Double[]:

public static void main(String[] args) {
    Foo<Double> f = new Foo<Double>();
    Double[] a2 = f.getA(); // throws ClassCastException
    System.out.println(a2);
}

Questo perché il tipo informazioni sulla variabile membro getA() viene cancellato in fase di esecuzione. Generics forniscono solo tipo di sicurezza a a tempo di compilazione (io ero in qualche modo ignorando questo nel mio post iniziale). Quindi il problema non è

private Object[] a = new Object[5];

perché a tempo di esecuzione di questo codice è davvero

<*>

Il problema si verifica quando il risultato del metodo di Object[], che in fase di esecuzione ritorna in realtà un <=>, viene assegnato ad un riferimento di tipo <=> - questa dichiarazione getta la ClassCastException perché oggetto non può essere lanciato a doppio <. / p>

Aggiorna 2 : per rispondere alla tua domanda finale: "Perché array rompere questo?" La risposta è perché le specifiche del linguaggio non supporta la creazione di matrice generica. Vedere questo post sul forum per ulteriori - al fine di essere compatibile, non si sa nulla sul tipo di T in fase di esecuzione.

Altri suggerimenti

Ci possono essere alcuni piccoli errori nella spiegazione di @ MattB.

L'errore è non

  

java.lang.Object non può essere gettato a java.lang.Double.

Si tratta di:

  

[Ljava.lang.Object; non può essere gettato a [Ljava.lang.Double

La [L indica un array. Cioè, l'errore è che un array di oggetti non può essere lanciato a una serie di doppio. Questo è lo stesso caso come segue:

Object[] oarr = new Object[10];
Double[] darr = (Double[]) oarr;

Questa ovviamente non è consentito.

Per il problema della creazione di array typesafe, Un'altra alternativa è quella se non un oggetto di classe in init e utilizzare Array.newInstance:

import java.lang.reflect.Array;

class Foo<T> {
  private T[] a ;

  public Foo(Class<T> tclass) {
    a = (T[]) Array.newInstance(tclass, 5);
  }

  public T[] getA() {
    return a;
  }

  public static <T> Foo<T> create(Class<T> tclass) {
    return new Foo<T>(tclass);
  }
}

class Array1
{
  public static final void main(final String[] args) {
    Foo<Double> f = Foo.create(Double.class);
    Double[] d = f.getA();
  }


}

@ Matt B: Grazie per la risposta! Molto utile.

Ho trovato una soluzione per coloro che sono interessati: dare il metodo geta un array inizializzato per popolare. In questo modo le informazioni tipo è disponibile.

public class Foo<T> {
  private T[] a = (T[]) new Object[5];

  public Foo() {
    // Add some elements to a
  }

  public T[] getA(T[] holdA) {
    // Check whether holdA is null and handle it...then:
    holdA = (T[]) Array.newInstance(holdA.getClass().getComponentType(), a.length);
    System.arraycopy(a, 0, holdA, 0, a.length);
    return holdA;
  }
}

Poi per il principale metodo:

public static void main(String[] args) {
  Foo<Double> f = new Foo<Double>();
  Double[] a2 = new Double[1];
  a2 = f.getA(a2);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top