Pregunta Convierta ArrayList en String [] array [duplicate]


Esta pregunta ya tiene una respuesta aquí:

Estoy trabajando en el entorno de Android y he intentado con el siguiente código, pero parece que no funciona.

String [] stockArr = (String[]) stock_list.toArray();

Si lo defino de la siguiente manera:

String [] stockArr = {"hello", "world"};

funciona. ¿Hay algo que me estoy perdiendo?


903
2018-03-21 05:57


origen


Respuestas:


Úselo así

List<String> stockList = new ArrayList<String>();
stockList.add("stock1");
stockList.add("stock2");

String[] stockArr = new String[stockList.size()];
stockArr = stockList.toArray(stockArr);

for(String s : stockArr)
    System.out.println(s);

1504
2018-03-21 06:07



Prueba esto

String[] arr = list.toArray(new String[list.size()]);

818
2018-03-21 06:03



Lo que está sucediendo es eso stock_list.toArray() está creando un Object[] preferible a String[] y, por lo tanto, el encasillado está fallando1.

El código correcto sería:

  String [] stockArr = stockList.toArray(new String[stockList.size()]);

o incluso

  String [] stockArr = stockList.toArray(new String[0]);

(Sorprendentemente, la última versión es más rápida en las versiones recientes de Java: ver https://stackoverflow.com/a/4042464/139985)

Para más detalles, refiérase a los javadocs para las dos sobrecargas de List.toArray.

(Desde una perspectiva técnica, la razón de este comportamiento / diseño de API es que una implementación de la List<T>.toArray() método no tiene información de lo que el <T> está en tiempo de ejecución. Todo lo que sabe es que el tipo de elemento sin procesar es Object. Por el contrario, en el otro caso, el parámetro de matriz proporciona el tipo de base de la matriz. (Si la matriz suministrada es lo suficientemente grande, se utiliza. De lo contrario, se asignará una nueva matriz del mismo tipo y un tamaño mayor y se devolverá como resultado).


1 - En Java, un Object[] no es una tarea compatible con un String[]. Si lo fuera, entonces podrías hacer esto:

    Object[] objects = new Object[]{new Cat("fluffy")};
    Dog[] dogs = (Dog[]) objects;
    Dog d = dogs[0];     // Huh???

Esto es claramente absurdo, y es por eso que los tipos de matriz generalmente no son compatibles con la asignación.


254
2018-03-21 06:05



Una alternativa en Java 8:

String[] strings = list.stream().toArray(String[]::new);

114
2018-04-20 01:58



Puedo ver muchas respuestas que muestran cómo resolver el problema, pero solo La respuesta de Stephen está tratando de explicar por qué ocurre un problema, así que intentaré agregar algo más sobre este tema. Es una historia sobre posibles razones por las cuales Object[] toArray no fue cambiado a T[] toArray donde se introdujeron los productos genéricos a Java.


Por qué String[] stockArr = (String[]) stock_list.toArray(); no funcionará?

En Java, el tipo genérico existe solo en tiempo de compilación. En tiempo de ejecución información sobre el tipo genérico (como en su caso <String>) se elimina y se reemplaza con Object tipo (echar un vistazo a tipo borrado) Es por eso que en tiempo de ejecución toArray() no tiene idea de qué tipo preciso usar para crear una nueva matriz, por lo que utiliza Object como el tipo más seguro, porque cada clase extiende Object para que pueda almacenar con seguridad la instancia de cualquier clase.

Ahora el problema es que no puedes lanzar instancia de Object[] a String[].

¿Por qué? Eche un vistazo a este ejemplo (supongamos que class B extends A)

//B extends A
A a = new A();
B b = (B)a;

Aunque tal código se compilará, en tiempo de ejecución veremos lanzado ClassCastException porque instancia sostenida por referencia a en realidad no es de tipo B (o sus subtipos). ¿Por qué este problema (por qué esta excepción debe ser emitida)? Una de las razones es que B podría tener nuevos métodos / campos que A no, por lo que es posible que alguien intente usar estos nuevos miembros a través de b referencia incluso si la instancia retenida no tiene (no los admite). En otras palabras, podríamos tratar de usar datos que no existen, lo que podría generar muchos problemas. Entonces, para evitar tal situación, JVM arroja una excepción y detiene el código potencialmente peligroso.

Podrías preguntar ahora "Entonces, ¿por qué no nos paramos incluso antes? ¿Por qué el código que involucra dicho casting es incluso compilable? ¿No debería el compilador detenerlo?". La respuesta es: no porque el compilador no puede saber con certeza cuál es el tipo real de instancia en poder de a referencia, y existe la posibilidad de que contenga instancia de clase B que apoyará la interfaz de b referencia. Echale un vistazo a éste ejemplo:

A a = new B(); 
      //  ^------ Here reference "a" holds instance of type B
B b = (B)a;    // so now casting is safe, now JVM is sure that `b` reference can 
               // safely access all members of B class

Ahora regresemos a sus matrices. Como ve en cuestión, no podemos emitir instancia de Object[] matriz de tipo más preciso String[] me gusta

Object[] arr = new Object[] { "ab", "cd" };
String[] arr2 = (String[]) arr;//ClassCastException will be thrown

Aquí el problema es un poco diferente. Ahora estamos seguros de que String[] array no tendrá campos o métodos adicionales porque cada matriz solo admite:

  • [] operador,
  • length archivado,
  • métodos heredados del supertipo Object,

Así es no la interfaz de matrices lo hace imposible. El problema es que Object[] conjunto al lado Strings puede almacenar cualquier objeto (por ejemplo Integers) así que es posible que un hermoso día terminemos intentando invocar un método como strArray[i].substring(1,3) en instancia de Integer que no tiene tal método.

Entonces para hacer Por supuesto que esta situación Nunca suceder, en Java las referencias de matriz solo pueden contener

  • instancias de matriz del mismo tipo como referencia (referencia String[] strArr puede aguantar String[])
  • instancias de matriz de subtipo (Object[] puede aguantar String[] porque String es un subtipo de Object),

pero no puede contener

  • matriz de supertipo de tipo de matriz de referencia (String[] no puede contener Object[])
  • array de tipo que no está relacionado con el tipo de referencia (Integer[] no puede contener String[])

En otras palabras, algo así está bien

Object[] arr = new String[] { "ab", "cd" }; //OK - because
               //  ^^^^^^^^                  `arr` holds array of subtype of Object (String)
String[] arr2 = (String[]) arr; //OK - `arr2` reference will hold same array of same type as 
                                //     reference

Podría decirse que una forma de resolver este problema es encontrar en tiempo de ejecución el tipo más común entre todos los elementos de lista y crear una matriz de ese tipo, pero esto no funcionará en situaciones donde todos los elementos de la lista serán de un tipo derivado de uno genérico. Echar un vistazo

//B extends A
List<A> elements = new ArrayList<A>();
elements.add(new B());
elements.add(new B());

ahora el tipo más común es Bno A asi que toArray() 

A[] arr = elements.toArray();

devolvería matriz de B clase new B[]. El problema con esta matriz es que mientras el compilador le permite editar su contenido al agregar new A() elemento para ello, obtendrías ArrayStoreException porque B[] array puede contener solo elementos de clase B o su subclase, para asegurarse de que todos los elementos admitirán la interfaz de B, pero instancia de A puede no tener todos los métodos / campos de B. Entonces esta solución no es perfecta.


La mejor solución a este problema es explícitamente decir qué tipo de matriz toArray() debe devolverse pasando este tipo como argumento de método como

String[] arr = list.toArray(new String[list.size()]);

o

String[] arr = list.toArray(new String[0]); //if size of array is smaller then list it will be automatically adjusted.

81
2017-07-28 14:19



La forma correcta de hacer esto es:

String[] stockArr = stock_list.toArray(new String[stock_list.size()]);

Me gustaría agregar a las otras excelentes respuestas aquí y explicar cómo podría haber utilizado los Javadocs para responder su pregunta.

El Javadoc para toArray() (sin argumentos) es aquí. Como puede ver, este método devuelve un Object[] y no  String[] que es una matriz del tipo de tiempo de ejecución de su lista:

public Object[] toArray() 

Devuelve una matriz que contiene todos los   elementos en esta colección. Si la colección hace alguna garantía como   a qué orden sus elementos son devueltos por su iterador, este método   debe devolver los elementos en el mismo orden La matriz devuelta será   "seguro" en el sentido de que la colección no mantiene referencias al mismo.   (En otras palabras, este método debe asignar una nueva matriz, incluso si el   la colección está respaldada por una matriz). La persona que llama es libre de modificar   la matriz devuelta

Justo debajo de ese método, sin embargo, es el Javadoc para toArray(T[] a). Como puede ver, este método devuelve un T[] dónde T es el tipo de arreglo que usted ingresa. Al principio, esto parece lo que está buscando, pero no está claro exactamente por qué está pasando un conjunto (¿lo está agregando, usándolo solo para el tipo, etc.)? . La documentación deja en claro que el propósito del conjunto pasado es esencialmente definir el tipo de matriz a devolver (que es exactamente su caso de uso):

public <T> T[] toArray(T[] a)

Devuelve una matriz que contiene todos los   elementos en esta colección; el tipo de tiempo de ejecución de la matriz devuelta es   el de la matriz especificada Si la colección se ajusta a lo especificado   matriz, se devuelve allí. De lo contrario, se asigna una nueva matriz   con el tipo de tiempo de ejecución de la matriz especificada y el tamaño de este   colección. Si la colección se ajusta a la matriz especificada con espacio para   de repuesto (es decir, la matriz tiene más elementos que la colección), el   elemento en la matriz inmediatamente después del final de la colección   está configurado a nulo. Esto es útil para determinar la duración de la   colección solo si la persona que llama sabe que la colección no   contiene cualquier elemento nulo.)

Si esta colección hace alguna garantía en cuanto a qué orden sus elementos   son devueltos por su iterador, este método debe devolver los elementos en   el mismo orden

Esta implementación comprueba si la matriz es lo suficientemente grande como para contener el   colección; si no, asigna una nueva matriz del tamaño correcto y   tipo (usando reflexión). Luego, itera sobre la colección,   almacenar cada referencia de objeto en el siguiente elemento consecutivo de   matriz, comenzando con el elemento 0. Si la matriz es más grande que el   colección, un nulo se almacena en la primera ubicación después del final de   la colección.

Por supuesto, se requiere una comprensión de los genéricos (como se describe en las otras respuestas) para comprender realmente la diferencia entre estos dos métodos. Sin embargo, si va primero a los Javadocs, generalmente encontrará su respuesta y luego verá por usted mismo qué más debe aprender (si realmente lo hace).

También tenga en cuenta que leer los Javadocs aquí le ayuda a comprender cuál debe ser la estructura de la matriz que pasa. Aunque en realidad no importa, no debes pasar una matriz vacía como esta:

String [] stockArr = stockList.toArray(new String[0]);  

Porque, desde el documento, esta implementación comprueba si la matriz es lo suficientemente grande como para contener la colección; si no, asigna una nueva matriz del tamaño y tipo correctos (utilizando la reflexión). No hay necesidad de gastos adicionales en la creación de una nueva matriz cuando puede pasar fácilmente el tamaño.

Como suele ser el caso, los Javadocs le brindan una gran cantidad de información y dirección.

Oye, espera un momento, ¿qué es el reflejo?


16
2017-07-28 15:31