2012-09-11 84 views
30
Object[] o = "a;b;c".split(";"); 
o[0] = 42; 

tirostratar de un ArrayStoreException

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 manera de tratar con esa excepción sin crear una matriz temporal String[]?

+4

Objeto [] o = "a; b; c" .split (";"); o [0] = 42; aquí está creando una matriz de cadenas, mientras que el objeto [] o = nuevo objeto [s.length]; es una matriz de Objetos. – Satya

Respuesta

53

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

Se puede retener un objeto de un subtipoen 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 ha roto de alguna manera. String[] se considera un subtipo de Object[], pero eso es mal! 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 con 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.

problema es que String[] sólo es compatible con una parte de Object[] contrato. Por ejemplo, puede leerObject valores de Object[]. Y también puede leerObject valores (que resultan ser objetos String) de String[]. Hasta aquí todo bien. El problema es con la otra parte del contrato. Puede poner cualquierObject en Object[]. Pero no puede poner Object en String[]. Por lo tanto, String[] no se debe considerar 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ó correctamenteList<String> es no un subtipo de List<Object>;. Y si usted quiere tener un supertipo común para estos, necesita List<?>, que es de solo lectura.Así es como debería ser también con 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[]. Puede ponerlo en una variable Object[], pero el objeto sigue siendo String[]. Es por eso que rechaza un valor de Integer. Debe crear una nueva matriz Objects[] y copiar los valores. Puede usar la función System.arraycopy para copiar los datos, pero no puede evitar crear la nueva matriz.

+0

http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#FAQ102 –

6

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

La matriz que devuelve split es en realidad un String[], y Java le permite asignarla a una variable del tipo Object[]. Todavía es realmente un String[] sin embargo, así que cuando intentas almacenar algo más que String en él, obtendrás un ArrayStoreException.

Para obtener información de antecedentes, consulte 4.10.3. Subtyping among Array Types en la Especificación del lenguaje Java.

0

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, se 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); 
-1

Si no es necesario el uso de un "split" .. Entonces puede evitar copiar ...

Cuestiones relacionadas