Traitement d'une ArrayStoreException


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

Jette

java.lang.ArrayStoreException: java.lang.Integer

Tandis que

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;

Non.

Existe-t-il un autre moyen de gérer cette exception sans créer un tableau String[] temporaire?

Author: sp00m, 2012-09-11

3 answers

En Java, un tableau est également un objet .

, Vous pouvez mettre un objet de sous-type dans une variable de supertype. Par exemple, vous pouvez mettre un objet String dans une variable Object.

Malheureusement, la définition du tableau en Java est en quelque sorte cassée. String[] est considéré comme un sous-type de Object[], mais c'est tort! Pour une explication plus détaillée, lisez à propos de "covariance et contravariance", mais l'essence c'est ceci: Un type doit être considéré un sous-type d'un autre type uniquement si le sous-type remplit toutes les obligations du supertype. Cela signifie que si vous obtenez un objet sous-type au lieu d'un objet supertype, vous ne devez pas vous attendre à un comportement contradictoire avec le contrat supertype.

Le problème est que String[]ne prend en charge qu'une partie du contrat Object[]. Par exemple, vous pouvez lire Object les valeurs de Object[]. Et vous pouvez aussi lire Object valeurs (qui se trouvent être des objets String) de String[]. Jusqu'à présent, pour Bien. Le problème est avec l'autre partie du contrat. Vous pouvez mettre tout Object dans Object[]. Mais vous ne pouvez pas mettre tout Object dans String[]. Par conséquent, String[] ne doit pas être considéré comme un sous-type de Object[], mais la spécification Java le dit. Et donc nous avons des conséquences comme celle-ci.

(Notez qu'une situation similaire est apparue à nouveau avec les classes génériques, mais cette fois, elle a été résolue correctement . List<String> est pas un sous-type de List<Object>; et si vous voulez avoir un supertype commun pour ceux - ci, vous avez besoin de List<?>, qui est en lecture seule. C'est comme ça que ça devrait être aussi avec les tableaux; mais ce n'est pas le cas. Et à cause de la rétrocompatibilité, il est trop tard pour le changer.)

Dans votre premier exemple, la fonction String.split crée un objet String[]. Vous pouvez le mettre dans une variable Object[], mais l'objet reste String[]. C'est pourquoi il rejette une valeur Integer. Vous devez créer un nouveau tableau Objects[] et copier les valeurs. Vous pouvez utiliser la fonction System.arraycopy pour copier les données, mais vous ne pouvez pas éviter de créer le nouveau tableau.

 64
Author: Viliam Búr, 2012-09-11 13:02:26

Non, il n'y a aucun moyen d'éviter de copier le tableau que split renvoie.

Le tableau que split renvoie est en fait un String[], et Java vous permet de l'affecter à une variable de type Object[]. C'est toujours vraiment un String[] cependant, donc lorsque vous essayez de stocker autre chose qu'un String, vous obtiendrez un ArrayStoreException.

Pour des informations générales, voir 4.10.3. Sous-typage parmi les types de tableau dans la spécification du langage Java.

 7
Author: Jesper, 2012-09-11 12:44:01

Il y a bien sûr d'autres options, comme celle que vous implémentez votre propre méthode split, qui renvoie directement un tableau d'objets. Je ne sais pas si ce qui vous dérange réellement avec le tableau de chaînes temporaire?

BTW, vous pouvez raccourcir votre code avec quelques lignes en utilisant System.arrayCopy au lieu d'implémenter votre propre boucle pour copier les éléments du tableau:

System.arrayCopy(s, 0, o, 0, s.length);
 0
Author: jarnbjo, 2012-09-11 13:03:53