Inesperado adicionando String para List <inteiros>

John :

Eu não entendo como a alça compilador é o seguinte código como ele gera Teste enquanto eu estava esperando um erro.

List<Integer> b = new ArrayList<Integer>();
List a = b;
a.add("test");
System.out.println(b.get(0));

Eu estava esperando que alguém poderia me dizer os exatos passos que o compilador faz quando executar o código para que eu possa entender a saída. O meu entendimento atual é que:

  1. O compilador verifica durante o tempo de compilação se um método add que suporta o tipo de argumento existe na lista de classe que é add (Object e) como sua matéria-digitado.
  2. No entanto, durante a execução que tenta chamar add (Object e) do objeto real List <Integer> que não detém este método como o objeto real não é matéria-digitado e, em vez detém o método add (Integer e) .

Se não houver um add (Object e) método no objeto real List <Integer> como se ainda de alguma forma adicionar uma String para a lista de inteiros?

Ray Toal:

Você está muito perto. As verificações de tempo de compilação todos pan out:

aé do tipo Listque a chamada

a.add("test");

garimpa para fora. bé de (tempo de compilação) tipo ArrayList<Integer>assim

b.get(0)

cheques para fora também. Note-se que as verificações são feitas apenas contra os tipos em tempo de compilação das variáveis . Quando o compilador vê a.add("test")ele não sabe o valor tempo de execução do objeto referenciado pela variável a. Em geral, ele realmente não pode (não há um resultado em ciência da computação teórica sobre este), embora a análise tipo de controle de fluxo pode pegar muitas dessas coisas. Linguagens como typescript pode fazer coisas incríveis em tempo de compilação.

Agora você pode assumir que em tempo de execução tais coisas poderiam ser verificado. Infelizmente, em Java que não pode. Java apaga tipos genéricos. Encontre um artigo sobre Java tipo de apagamento para os detalhes. O TL; DR é que uma List<Integer>em tempo de compilação se torna uma matéria Listem tempo de execução. A JVM não tem uma maneira de "reificam" genéricos (embora outras línguas fazer!) Por isso, quando os genéricos foram introduzidos, foi tomada a decisão de que Java seria apenas apagar os tipos genéricos. Assim, em tempo de execução, não há nenhum problema digite seu código.

Vamos dar uma olhada no código compilado:

   0: new           #2                  // class java/util/ArrayList
   3: dup
   4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
   7: astore_1
   8: aload_1
   9: astore_2
  10: aload_2
  11: ldc           #4                  // String test
  13: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
  18: pop
  19: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
  22: aload_1
  23: iconst_0
  24: invokeinterface #7,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
  29: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
  32: return

Aqui você pode ver diretamente que não há nenhum tipo de verificações em tempo de execução. Então, a resposta completa (mas aparentemente irreverente) à sua pergunta é que Java só verifica os tipos em tempo de compilação com base nos tipos de variáveis (conhecido em tempo de compilação), mas parâmetros de tipo genérico são apagados e o código é executado sem eles.

Acho que você gosta

Origin http://43.154.161.224:23101/article/api/json?id=181414&siteId=1
Recomendado
Clasificación