Domanda

Obiettivo


Sto facendo una classe Java che darà una maggiore usabilità agli array, come add, remove, e contains metodi. Ho pensato che la soluzione migliore è fare una classe (chiamata ArrayPP) che ha un parametro di tipo T. In questo modo, l'utente può interagire con il ArrayPP oggetto il più facilmente possibile con un array dello stesso tipo.

Problema


Ho rapidamente scoperto che metodi come add richiederà la creazione di un array separato e finirà per cambiare l'array di destinazione t da una serie di Ts in una serie di ObjectS. Come puoi immaginare, questo distrugge totalmente l'usabilità e quando provo a fare qualcosa di simile

File[] f = new File[0];
ArrayPP<File> appF = new ArrayPP(f);
appF.add(saveFile);
f = appF.toArray();

Il programma lancia

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.io.File;

perché il add Il metodo deve cambiare l'array in un array di ObjectS, poiché il compilatore Java non ti permetterà di creare un array generico (T[] t = new T[0]; è cattivo, ma T[] t = (T[]) new Object[0]; va bene). So dal debug di linea per riga che il codice sopra mantiene l'array t, in questo caso, come una matrice di Files fino alla 4a riga del add il metodo è chiamato. Qualcuno ha una soluzione che manterrà l'array t essendo una serie di Ts e non una serie di ObjectS?

Codice di esempio


Di seguito è riportata una versione molto annacquata della mia classe.

public class ArrayPP<T>
{
  T[] t;

  /**
   * Creates a new Array++ to manage the given array.
   * <h3>Analogy:</h3>
   * <tt>ArrayPP&lt;String&gt; s = new ArrayPP(args);</tt><br/>
   * is analogous to<br/>
   * <tt>String s[] = args;</tt>
   * @param array The array to be managed
   */
  public ArrayPP(T[] array)
  {
    t = array;
  }

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
    T[] temp = (T[]) new Object[t.length + 1];
    System.arraycopy(t, 0, temp, 0, t.length);
    temp[temp.length - 1] = val;
    t = (T[])temp;
    return this;
  }

  /**
   * Returns the array at the core of this wrapper
   * @return the array at the core of this wrapper
   */
  public T[] toArray()
  {
    return t;
  }
}

Possibile soluzione?


Dopo aver esaminato altre domande su array generici, penso di avere una soluzione:

Invece di

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
    T[] temp = (T[]) new Object[t.length + 1];
    System.arraycopy(t, 0, temp, 0, t.length);
    temp[temp.length - 1] = val;
    t = (T[])temp;
    return this;
  }

Funzionerà?

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP<T> add(T val)
  {
    t = java.util.Arrays.copyOf(t, t.length + 1);
    t[t.length - 1] = val;
    return this;
  }
È stato utile?

Soluzione

In linea di principio non è possibile creare facilmente array di un tipo generico (o una variabile di tipo).

Se si dispone di un oggetto di classe, è possibile utilizzare la riflessione o se hai un array di esempio, i metodi in java.util.Arrays Classe per creare una copia (più lunga/più corta). Ma non è elegante in entrambi i casi.

La classe ArrayList usa semplicemente un Object[] per archiviare i suoi elementi e convertire solo su get/set/aggiungi/toarray. Cosa farebbe la tua classe meglio di ArrayList?


Modificare:

Consiglierei semplicemente di delegare a una lista di arrays o fare l'implementazione come ArrayList, usando un Object[] internamente e convertire l'uscita ove necessario.

Se vuoi davvero avere una serie di tipo giusto internamente, è possibile - ma diventa brutto, come ho detto.

Il add Il metodo è ancora il caso più semplice:

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
     T[] temp = Arrays.copyOf(t, t.length+1);
     temp[t.length] = val;
     t = temp;
     return this;
  }

Quando vuoi aggiungere al centro o rimuovere, dovrai combinarlo con la tua ArrayCopy.

Altri suggerimenti

C'è qualche motivo per cui è costruito List<T> Classe (ES) non può fare ciò di cui hai bisogno? Come in:

String[] theArray = {"a", "b", "c"};
List<String> theList = Arrays.asList(theArray);
public ArrayPP(T[] array)
    componentClass = array.getClass().getComponentClass();

T[] newArray(int length)
    return Array.newInstance(componentClass, length)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top