Pergunta

import java.lang.reflect.Array;

public class PrimitiveArrayGeneric {
    static <T> T[] genericArrayNewInstance(Class<T> componentType) {
        return (T[]) Array.newInstance(componentType, 0);
    }

    public static void main(String args[]) {
        int[] intArray;
        Integer[] integerArray;

        intArray = (int[]) Array.newInstance(int.class, 0);
        // Okay!

        integerArray = genericArrayNewInstance(Integer.class);
        // Okay!

        intArray = genericArrayNewInstance(int.class);
        // Compile time error:
           // cannot convert from Integer[] to int[]

        integerArray = genericArrayNewInstance(int.class);
        // Run time error:
           // ClassCastException: [I cannot be cast to [Ljava.lang.Object;
    }    
}

Estou tentando entender completamente como os genéricos funcionam em Java.As coisas ficam um pouco estranhas para mim na terceira tarefa do trecho acima:o compilador está reclamando que Integer[] não pode ser convertido em int[].A afirmação é 100% verdadeira, é claro, mas estou me perguntando POR QUE o compilador está fazendo essa reclamação.

Se você comentar essa linha e seguir a "sugestão" do compilador como na 4ª tarefa, o compilador está realmente satisfeito!!! AGORA o código compila perfeitamente!O que é uma loucura, claro, já que, como sugere o comportamento do tempo de execução, int[] não pode ser convertido em Object[] (que é o que T[] é apagado em tempo de execução).

Então minha pergunta é:por que o compilador está "sugerindo" que eu atribua a Integer[] em vez disso, para a terceira tarefa?Como o compilador raciocina para chegar a essa conclusão (errônea!)?


Há muita confusão nas duas respostas até agora, então criei outro exemplo desconcertante para ilustrar o problema subjacente aqui:

public class PrimitiveClassGeneric {    
    static <T extends Number> T test(Class<T> c) {
        System.out.println(c.getName() + " extends " + c.getSuperclass());
        return (T) null;
    }
    public static void main(String args[]) {
        test(Integer.class);
        // "java.lang.Integer extends class java.lang.Number"

        test(int.class);
        // "int extends null"
    }
}

Eu sou o único que acha absolutamente louco que o compilador permita que o código acima seja compilado?

Não seria irracional imprimir c.getSuperclass().getName() no código acima, por exemplo, já que especifiquei que T extends Number.Claro agora getName() vai jogar NullPointerException quando c == int.class, desde c.getSuperclass() == null.

E para mim, esse é um bom motivo para rejeitar a compilação do código em primeiro lugar.


Talvez a loucura final:

    int.class.cast(null);

Esse código compila E funciona bem.

Foi útil?

Solução

O tipo de int.class é Class<Integer>, então genericArrayNewInstance() seria inferido para retornar um Integer[].Mas a função na verdade cria um int[], portanto, haveria uma exceção de conversão de classe quando fosse retornada.Basicamente, o elenco T[] dentro da função não é legítimo neste caso, porque int[] não é um T[] (primitivos não podem ser usados ​​em variáveis ​​de tipo).Você não pode lidar genericamente com tipos de array primitivos;então você precisa que seu método retorne o tipo Object, ou você terá que criar métodos separados para tipos de referência e para tipos primitivos.

Outras dicas

Alguns pontos:

  1. Primitivos são AutoBoxed para seus colegas de objetos (invólucros) quando necessário
  2. Matrizes primitivas são objetos, para que não sejam auto -boxados.
  3. Os genéricos não podem usar primitivas como parâmetros de tipo

Para seus exemplos, aqui estão minhas suposições:

Em 3, o autoboxing acontece com o Tipo parâmetro, mas não acontece com a matriz devolvida
Em 4, o autoboxing acontece com o Tipo parâmetro, mas não acontece com o argumento do método, então de fato um int[] é gerado, mas Integer[] é esperado

A auto -boxação no caso do parâmetro de tipo pode não ser exatamente AutoBoxing, mas é algo com a mesma ideia.

Atualizar: Seu segundo exemplo não tem nada errado. int.class é um Class, então o compilador não tem motivos para rejeitá -lo.

Eu concordo com o pôster original. Isso é loucura. Por que não posso usar o primitivo com genérico? Isso pode não ser um problema de compilador, mas é a questão do idioma. Simplesmente errado para pular tipos primitivos de genérico.

Por esta:

intarray = (int []) array.newInstance (int.class, 0);

Int.class é apenas um objeto de classe. Então, não há problema em passar. "Int" é um tipo, então não está ok, porque é claramente primitivo. Para não dizer que essa é a "melhor" maneira de criar o idioma, apenas para aderir ao idioma.

Isso é tão louco que não posso criar um invólucro para a alocação de memória (matriz) de primitivas usando genérico. Se estiver usando objetos, isso é tão inchado para uma enorme coleção que é um desperdício. As pessoas que criaram o idioma/máquina Java claramente têm um limite de bits em seu cérebro. Eles podem fazer errado na primeira vez, mas consertar leva uma década e não fazê -lo certo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top