java arrays casting type-conversion

java - Tratar con una ArrayStoreException



casting type-conversion (4)

En Java, una matriz también es un objeto .

Puede poner un objeto de un subtipo en una variable de un supertipo . Por ejemplo, puede poner un objeto String en una variable Object .

Desafortunadamente, la definición de matriz en Java se rompe de alguna manera. String[] se considera un subtipo de Object[] , pero eso es incorrecto . Para una explicación más detallada, lea sobre "covarianza y contravarianza", pero la esencia es esta: un tipo debe considerarse un subtipo de otro tipo solo si el subtipo cumple todas las obligaciones del supertipo. Esto significa que si obtiene un objeto de subtipo en lugar de un objeto de supertipo, no debe esperar un comportamiento contradictorio con un contrato de supertipo.

El problema es que String[] solo admite una parte del contrato Object[] . Por ejemplo, puede leer los valores de Object[] desde Object[] . Y también puede leer valores de Object (que resultan ser objetos de String ) de String[] . Hasta aquí todo bien. El problema es con la otra parte del contrato. Puedes poner cualquier Object en Object[] . Pero no puedes poner ningún Object en la String[] . Por lo tanto, String[] no debe considerarse un subtipo de Object[] , pero la especificación de Java dice que sí. Y así tenemos consecuencias como esta.

(Tenga en cuenta que una situación similar apareció de nuevo con las clases genéricas, pero esta vez se resolvió correctamente . List<String> no es un subtipo de List<Object> ; y si desea tener un supertipo común para estos, necesita List<?> , que es de solo lectura. Así es como debería ser también con las matrices, pero no lo es. Y debido a la compatibilidad con versiones anteriores, es demasiado tarde para cambiarlo).

En su primer ejemplo, la función String.split crea un objeto String[] . Puedes ponerlo en una variable Object[] , pero el objeto sigue siendo String[] . Es por eso que rechaza un valor Integer . Debe crear una nueva matriz de Objects[] y copiar los valores. Puede usar la función System.arraycopy para copiar los datos, pero no puede evitar crear la nueva matriz.

Object[] o = "a;b;c".split(";"); o[0] = 42;

tiros

java.lang.ArrayStoreException: java.lang.Integer

mientras

String[] s = "a;b;c".split(";"); Object[] o = new Object[s.length]; for (int i = 0; i < s.length; i++) { o[i] = s[i]; } o[0] = 42;

no.

¿Hay alguna otra forma de lidiar con esa excepción sin crear una matriz String[] temporal?


No, no hay forma de evitar copiar la matriz que split dividendos.

La matriz que split realidad es una String[] , y Java le permite asignarla a una variable de tipo Object[] . Sin embargo, todavía es realmente una String[] , así que cuando intentes almacenar algo más que una String , obtendrás una ArrayStoreException .

Para información de fondo, ver 4.10.3. Subtipo entre tipos de matrices en la especificación del lenguaje Java.


Por supuesto, existen otras opciones, como que implementa su propio método de división, que devuelve una matriz de objetos directamente. No estoy seguro de qué es lo que realmente te molesta con la matriz de cadenas temporal.

Por cierto, puede acortar su código con unas pocas líneas usando System.arrayCopy en lugar de implementar su propio bucle para copiar los elementos de la matriz:

System.arrayCopy(s, 0, o, 0, s.length);


Si no es necesario usar una "división" ... Entonces puede evitar copiar ...