pass into from convertir como asarray array java arrays generics

java - into - pass arraylist to array



Genéricos de Java en ArrayList.toArray() (8)

Puedo, y usaré un iterador en lugar de hacer una matriz a veces, pero esto siempre me pareció extraño. ¿Por qué el método get (x) sabe lo que está devolviendo, pero toArray () está predeterminado en Objetos? Es como a mitad de camino para diseñarlo, ¿decidieron que esto no era necesario aquí?

Como la intención de la pregunta parece no ser solo moverse usando toArray() con genéricos, sino también comprender el diseño de los métodos en la clase ArrayList , me gustaría agregar:

ArrayList es una clase genérica, ya que se declara como

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable

lo que hace posible utilizar métodos genéricos como public E get(int index) dentro de la clase.

Pero si un método como toArray() no devuelve E , sino E[] , las cosas comienzan a ponerse un poco complicadas. No sería posible ofrecer una firma como public <E> E[] toArray() porque no es posible crear matrices genéricas.

La creación de matrices se produce en tiempo de ejecución y, debido a la eliminación de tipo , el tiempo de ejecución de Java no tiene información específica del tipo representado por E La única solución a partir de ahora es pasar el tipo requerido como parámetro al método y, por lo tanto, la firma public <T> T[] toArray(T[] a) donde los clientes se ven obligados a pasar el tipo requerido.

Pero, por otro lado, funciona para el public E get(int index) porque si observa la implementación del método, encontrará que a pesar de que el método utiliza la misma matriz de Object para devolver el elemento en el valor especificado índice, se lanza a E

E elementData(int index) { return (E) elementData[index]; }

Es el compilador de Java que en el momento de la compilación reemplaza E con Object

Supongamos que tiene una lista de arrays definida de la siguiente manera:

ArrayList<String> someData = new ArrayList<>();

Más adelante en su código, debido a los genéricos, puede decir esto:

String someLine = someData.get(0);

Y el compilador sabe directamente que obtendrá una cadena. Yay genéricos! Sin embargo, esto fallará:

String[] arrayOfData = someData.toArray();

toArray() siempre devolverá una matriz de objetos, no del genérico que se definió. ¿Por qué el método get(x) sabe lo que está devolviendo, pero toArray() predeterminado en Objetos?


Es posible crear una matriz "genérica" ​​del tipo dado (conocido). Normalmente uso algo como esto en mi código.

public static <T> T[] toArray(Class<T> type, ArrayList<T> arrList) { if ((arrList == null) || (arrList.size() == 0)) return null; Object arr = Array.newInstance(type, arrList.size()); for (int i=0; i < arrList.size(); i++) Array.set(arr, i, arrList.get(i)); return (T[])arr; }


La información genérica se erased en tiempo de ejecución. JVM no sabe si su lista es List<String> o List<Integer> (en tiempo de ejecución T en List<T> se resuelve como Object ), por lo que el único tipo de matriz posible es Object[] .

Sin toArray(T[] array) puede usar toArray(T[] array) ; en este caso, JVM puede usar la clase de una matriz determinada, puede verla en la implementación de ArrayList :

public <T> T[] toArray(T[] a) { if (a.length < size) // Make a new array of a''s runtime type, but my contents: return (T[]) Arrays.copyOf(elementData, size, a.getClass());


Lo pertinente a tener en cuenta es que las matrices en Java conocen su tipo de componente en tiempo de ejecución. String[] e Integer[] son clases diferentes en tiempo de ejecución, y puede solicitar a las matrices su tipo de componente en tiempo de ejecución. Por lo tanto, se necesita un tipo de componente en tiempo de ejecución (ya sea codificando de forma rígida un tipo de componente reificable en tiempo de compilación con una new String[...] o utilizando Array.newInstance() y pasando un objeto de clase) para crear una matriz.

Por otro lado, los argumentos de tipo en genéricos no existen en tiempo de ejecución. No hay absolutamente ninguna diferencia en tiempo de ejecución entre una ArrayList<String> y una ArrayList<Integer> . Todo es solo ArrayList .

Esa es la razón fundamental por la que no puede simplemente tomar una List<String> y obtener una String[] sin pasar el tipo de componente por separado de alguna manera: tendría que obtener información del tipo de componente de algo que no tiene tipo de componente información. Claramente, esto es imposible.


Lo primero que debe entender es que lo que posee ArrayList es solo una matriz de Object

transient Object[] elementData;

Cuando se trata de la razón por la cual T[] falla, es porque no se puede obtener una matriz de tipo genérico sin una Class<T> y esto se debe a que borra el tipo de Java ( hay más explicaciones y cómo crear una ) . Y la array[] en el montón conoce su tipo dinámicamente y no puede convertir int[] en String[] . La misma razón, no puedes lanzar Object[] a T[] .

int[] ints = new int[3]; String[] strings = (String[]) ints;//java: incompatible types: int[] cannot be converted to java.lang.String[] public <T> T[] a() { Object[] objects = new Object[3]; return (T[])objects; } //ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer; Integer[] a = new LearnArray().<Integer>a();

Pero lo que pones en la array es solo un objeto cuyo tipo es E (que es verificado por el compilador), por lo que puedes convertirlo a E que es seguro y correcto.

return (E) elementData[index];

En resumen, no puedes obtener lo que no tienes por elenco. Solo tiene Object[] , por lo que toArray() puede devolver Object[] (de lo contrario, debe darle una Class<T> para hacer una nueva matriz con este tipo). ArrayList<E> E en ArrayList<E> , puedes obtener una E con get() .


Si mira el Javadoc para la interfaz de List , notará una segunda forma de toArray : <T> T[] toArray(T[] a) .

De hecho, el Javadoc incluso da un ejemplo de cómo hacer exactamente lo que quieres hacer:

String[] y = x.toArray(new String[0]);


Si observa la implementación de toArray(T[] a) de la clase ArrayList<E> , es como:

public <T> T[] toArray(T[] a) { if (a.length < size) // Make a new array of a''s runtime type, but my contents: return (T[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; }

El problema con este método es que necesita pasar una matriz del mismo tipo genérico. Ahora considere si este método no toma ningún argumento, entonces la implementación sería algo similar a:

public <T> T[] toArray() { T[] t = new T[size]; // compilation error return Arrays.copyOf(elementData, size, t.getClass()); }

Pero el problema aquí es que no puede crear matrices genéricas en Java porque el compilador no sabe exactamente qué representa T En otras palabras, la creación de una matriz de un tipo no reificable ( JLS §4.7 ) no está permitida en Java .

Otra cita importante de Array Store Exception ( JLS §10.5 ):

Si el tipo de componente de una matriz no fuera reificable (§4.7), la Máquina virtual Java no podría realizar la verificación de la tienda descrita en el párrafo anterior. Es por eso que una expresión de creación de matriz con un tipo de elemento no reifiable está prohibida (§15.10.1).

Es por eso que Java ha proporcionado una versión sobrecargada a toArray(T[] a) .

Reemplazaré el método toArray () para decirle que devolverá una matriz de E.

Entonces, en lugar de anular toArray() , debe usar toArray(T[] a) .

No se pueden crear instancias de parámetros de tipo desde Java Doc también puede ser interesante para usted.


Una matriz es de un tipo diferente al tipo de matriz. Es una especie de clase StringArray en lugar de la clase String.

Suponiendo que sería posible, un método genérico para toArray() se vería así

private <T> T[] toArray() { T[] result = new T[length]; //populate return result; }

Ahora durante la compilación, el tipo T se borra. ¿Cómo se debe reemplazar la parte new T[length] ? La información de tipo genérico no está disponible.

Si observa el código fuente de (por ejemplo) ArrayList , verá lo mismo. El toArray(T[] a) llena la matriz dada (si el tamaño coincide) o crea una nueva matriz nueva usando el tipo de parámetro, que es el tipo de matriz del tipo genérico T.