Antes de explicar, vale notar que se for assim, funciona:
Integer[] numeros = {1, 2, 3};
Object[] objects = numeros;
Integer[] outrosNumeros = (Integer[]) objects;
System.out.println(Arrays.toString(outrosNumeros)); // [1, 2, 3]
O que de fato faz sentido: pode ser feito um cast de um array de Object
para um array de Integer
, já que um Object
também pode ser casteado para um Integer
. O código compila e roda sem problemas.
Mas por que isso não funciona?
List teste = new ArrayList();
teste.add(0);
teste.add(0);
Object[] objectTest = teste.toArray();
// ERRO: ClassCastException
Integer[] newStringArray = (Integer[]) objectTest;
Teoricamente, é a mesma coisa, certo? A princípio parece que sim, mas se olharmos por debaixo dos panos descobriremos a causa.
Um array guarda a informação do seu tipo, que você pode ver imprimindo o próprio array:
Integer[] numeros = {1, 2, 3};
System.out.println(numeros);
Object[] objects = numeros;
System.out.println(objects);
Integer[] outrosNumeros = (Integer[]) objects;
System.out.println(outrosNumeros);
A saída é:
[Ljava.lang.Integer;@6bc7c054
[Ljava.lang.Integer;@6bc7c054
[Ljava.lang.Integer;@6bc7c054
No caso, o [
indica que é um array, o L
indica que é uma classe/interface e em seguida vem o nome da classe - este formato está descrito em mais detalhes aqui (o restante depois da @
é o hashcode do objeto, que não é relevante para esta explicação - só vale notar que é o mesmo em todas as linhas, afinal, trata-se do mesmo array).
Repare que mesmo que o array esteja guardado em uma variável do tipo Object[]
, ainda sim em runtime ele guarda a informação do tipo original dos seus elementos, que é Integer
. Por isso ao fazer o cast de volta para Integer[]
não dá erro ao executar o código.
Mas quando obtemos o array de um ArrayList
, veja o que ocorre:
List teste = new ArrayList();
teste.add(0);
teste.add(0);
Object[] objectTest = teste.toArray();
System.out.println(objectTest);
Este código imprime:
[Ljava.lang.Object;@232204a1
Ou seja, o array retornado guarda a informação de que o tipo dos seus elementos é Object
. Por isso ao fazer cast para Integer[]
dá um ClassCastException
, pois o tipo que está associado ao array é Object
, e não Integer
.
Agora se eu fizesse assim:
Object[] objectTest = teste.toArray(new Integer[0]);
System.out.println(objectTest);
Aí imprime [Ljava.lang.Integer;@232204a1
, ou seja, o array passa a ter o tipo correto e tudo funciona.