Pergunta

Eu vi isso em uma resposta para outra pergunta, em referência às deficiências da especificação Java:

Existem mais deficiências e este é um tópico sutil.Verificar esse fora:

public class methodOverloading{
     public static void hello(Integer x){
          System.out.println("Integer");
     }

     public static void hello(long x){
          System.out.println("long");
     }

     public static void main(String[] args){
         int i = 5;
         hello(i);
     }
}

Aqui, "longo" seria impresso (não verifiquei), porque o compilador escolhe a ampliação em vez do boxe automático.Tenha cuidado ao usar o boxe automático ou simplesmente não o use!

Temos certeza de que este é realmente um exemplo de ampliação em vez de autoboxing, ou é algo totalmente diferente?

Na minha varredura inicial, eu concordaria com a afirmação de que a saída seria "longa" com base em i sendo declarado como um primitivo e não um objeto.No entanto, se você mudou

hello(long x)

para

hello(Long x)

a saída imprimiria "Inteiro"

O que realmente está acontecendo aqui?Não sei nada sobre compiladores/interpretadores de bytecode para java...

Foi útil?

Solução

No primeiro caso, você tem uma conversão ampliada acontecendo.Isso pode ser visto ao executar o programa utilitário "javap" (incluído com o JDK), na classe compilada:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_ 5
   1:   istore_ 1
   2:   iload_ 1
   3:   i2l
   4:   invokestatic    #6; //Method hello:(J)V
   7:   return

}

Claramente, você vê o I2L, que é o mnemônico para a instrução de alargamento do bytecode Integer-To-Long.Ver referência aqui.

E no outro caso, substituindo o "long x" pela assinatura do objeto "Long x", você terá este código no método principal:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_ 5
   1:   istore_ 1
   2:   iload_ 1
   3:   invokestatic    #6; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   6:   invokestatic    #7; //Method hello:(Ljava/lang/Integer;)V
   9:   return

}

Então você vê que o compilador criou a instrução Integer.valueOf(int), para encaixar o primitivo dentro do wrapper.

Outras dicas

Sim, é, experimente em um teste.Você verá “longo” impresso.Ele está se ampliando porque o Java escolherá ampliar o int para um long antes de optar por autoboxá-lo para um número inteiro, portanto, o método hello(long) é escolhido para ser chamado.

Editar: a postagem original sendo referenciada.

Edição adicional:A razão pela qual a segunda opção imprimiria Inteiro é porque não há "alargamento" para um primitivo maior como opção, portanto DEVE encaixá-lo, portanto Inteiro é a única opção.Além disso, o java fará o autobox apenas para o tipo original, portanto, ocorreria um erro do compilador se você deixasse o hello (Long) e removesse o hello (Integer).

Outra coisa interessante neste exemplo é a sobrecarga do método.A combinação de ampliação de tipo e sobrecarga de método só funciona porque o compilador precisa tomar uma decisão sobre qual método escolher.Considere o seguinte exemplo:

public static void hello(Collection x){
   System.out.println("Collection");
}

public static void hello(List x){
   System.out.println("List");
}

public static void main(String[] args){
   Collection col = new ArrayList();
   hello(col);
}

Ele não usa o tipo de tempo de execução que é Lista, ele usa o tipo de tempo de compilação que é Coleção e, portanto, imprime "Coleção".

Eu encorajo você a ler Java eficaz, o que abriu meus olhos para alguns casos secundários do JLS.

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