2015-12-24 17 views
7

Viene visualizzato un errore ClassCastException durante l'esecuzione a causa dell'implicazione implicita di d in una doppia quando si esegue il codice. Tuttavia, se cambio riferimento a d in Object[], non può essere un parametro della funzione impostata. Se cambio la funzione set per accettare un Object[] allora tutto funziona correttamente, ma poi la classe fallirà in fase di esecuzione se qualcuno chiama impostato su un oggetto che non è di tipo N.Restituzione di una matrice da una classe generica

Ho bisogno di una soluzione che possa get() il vecchio array (o un suo clone) e che possa dati set() in un nuovo array.

public class Foo<N> { 

    public static void main(String[] args) { 
     Foo<Double> foo = new Foo<Double>(); 
     Double[] d = foo.get(); 

     // do stuff to d ... 

     foo.set(d); 
    } 

    N[] data; 

    public Foo() { 
     data = (N[]) new Object[2]; 
    } 

    public N[] get() { 
     return (N[]) data; 
    } 

    public void set(N[] data) { 
     this.data = data; 
    } 

} 
+1

Possibile duplicato di [Come creare un array generico in Java?] (Http://stackoverflow.com/questions/529085/how-to-create-a-generic-array-in-java) – Julien

+0

Non è un duplicato di quello q. – avisnacks

+0

è possibile utilizzare questo http: // stackoverflow.it/a/3403976/2513573 per estrarre il tipo e Array.newInstance per creare l'array – AdamSkywalker

risposta

1

Per creare un array con il tipo di runtime corretto è necessario un tipo di rappresentazione runtime di quel tipo. Una classe generica come Foo<N> non ha una rappresentazione runtime di N.

ci sono due soluzioni:

  1. utilizzare un List<N> invece. Questo è meglio se è possibile!
  2. Aggiungere manualmente una rappresentazione runtime di N passando da Class<N> a Foo, utilizzare java.lang.reflect.Array.newInstance per creare l'array.

Codice per la seconda soluzione:

public Foo(Class<N> newDataClass) { 
    data = (N[]) Array.newInstance(newDataClass, 2); 
} 

Foo<Double> foo = new Foo<>(Double.class); 

EDIT:

Se ciò che si vuole fare è invece di ottenere una copia di un Double matrice esistente si può fare quello con (N[]) data.clone(). Impostarlo non sarà un problema.

1

C'è un trucco per questo.

class Foo<N> { 

    // Deliberately no parameters. 
    N[] myArray = makeArray(); 

    private N[] makeArray(N... ns) { 
     return ns; 
    } 

    public N[] get() { 
     return myArray; 
    } 
} 

Questo può sembrare non c'è casting (che è una buona cosa), ma in realtà non c'è, è solo stato fatto dal sistema varargs.

+0

Forse non ero chiaro w la domanda, ma nel mio caso l'array è già istanziato e ho bisogno di apportare una modifica ad esso. Quindi ho bisogno di fartelo fare da qualcosa. E resettalo. Non posso avere una soluzione che la instanzia nel costruttore. – avisnacks

+2

@avisnacks: nel tuo esempio crei la matrice nel costruttore 'Foo'. Non è così che dovrebbe funzionare? Puoi aggiornare la domanda per renderla più chiara? – Lii

+0

@OldCurmudgeon: questo non funziona. Otterrai sempre una matrice 'Object' in' myArray'. Quando l'inizializzatore chiama 'makeArray' non c'è traccia di' N' sinistra, è stato cancellato. Il metodo generico vararg crea sempre matrici 'Object'. Non è possibile creare array di tipo generico. Questo è descritto ad esempio nel [tutorial Java] (https://docs.oracle.com/javase/tutorial/java/generics/restrictions.html#createArray). – Lii

1

Un modo comodo (ma dettagliato) per farlo sarebbe quello di cambiare il costruttore per prendere un argomento fittizio con il tipo di matrice, poiché si sa che è doppio nel metodo principale.

public class Foo<N> { 
     N[] data; 

     public Foo(N inType) { 
      data = (N[]) Array.newInstance(inType.getClass(), 2) ; 
     } 

     public N[] get() { 
      return (N[]) data; 
     } 

     public void set(N[] data) { 
      this.data = data; 
     } 

     public static void main(String[] args) { 
      Foo<Double> foo = new Foo<Double>(new Double(0)); 
      Double[] d = foo.get(); 
      // do stuff to d ... 
      foo.set(d); 
     } 

    } 
0

Il problema con un generico è che non ha alcun tipo specifico in fase di esecuzione. È solo la classe Object, il che significa che la creazione di tale oggetto è completamente inutile, perché in effetti si creerebbe semplicemente un oggetto di tipo Object.

È tuttavia possibile creare tali oggetti dall'esterno della classe, poiché il tipo reale dell'oggetto è noto qui (Double). Quindi suggerirei di usare una sorta di List, che può essere dinamico, per memorizzare i valori.

Problemi correlati