Como a class String substitui o operador +?

Por que, em Java, você pode adicionar Strings com o operador +, quando String é uma class? No código String.java , não encontrei nenhuma implementação para esse operador. Este conceito viola a orientação a objects?

Vamos ver as seguintes expressões simples em Java

 int x=15; String temp="x = "+x; 

O compilador converte "x = "+x; em um StringBuilder internamente e usa .append(int) para “adicionar” o inteiro à string.

5.1.11. Conversão de String

Qualquer tipo pode ser convertido para digitar String por conversão de string.

Um valor x do tipo primitivo T é primeiro convertido em um valor de referência como se dando-o como um argumento para uma expressão de criação de instância de class apropriada (§15.9):

  • Se T for booleano, use new Boolean (x).
  • Se T é char, use o novo caractere (x).
  • Se T for byte, short ou int, use o novo Integer (x).
  • Se T for longo, use o novo Long (x).
  • Se T for float, use o novo Float (x).
  • Se T for duplo, use o novo Double (x).

Este valor de referência é então convertido para o tipo String por conversão de string.

Agora apenas os valores de referência precisam ser considerados:

  • Se a referência é nula, ela é convertida para a string “null” (quatro caracteres ASCII n, u, l, l).
  • Caso contrário, a conversão é executada como se por uma invocação do método toString do object referenciado sem argumentos; mas se o resultado de chamar o método toString for nulo, a cadeia “null” será usada.

O método toString é definido pela class primordial Object (§4.3.2). Muitas classs substituem, notadamente Boolean, Character, Integer, Long, Float, Double e String.

Veja §5.4 para detalhes do contexto de conversão de string.

15.18.1.

Otimização da Concatenação de Cadeia: Uma implementação pode optar por executar conversão e concatenação em uma única etapa para evitar a criação e descarte de um object String intermediário. Para aumentar o desempenho da concatenação de cadeias repetidas, um compilador Java pode usar a class StringBuffer ou uma técnica semelhante para reduzir o número de objects String intermediários que são criados pela avaliação de uma expressão.

Para tipos primitivos, uma implementação também pode otimizar a criação de um object de invólucro, convertendo diretamente de um tipo primitivo para uma cadeia de caracteres.

A versão otimizada não fará uma conversão completa de string primeiro.

Esta é uma boa ilustração de uma versão otimizada usada pelo compilador, embora sem a conversão de uma primitiva, onde você pode ver o compilador alterando as coisas para um StringBuilder em segundo plano:

http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/


Este código java:

 public static void main(String[] args) { String cip = "cip"; String ciop = "ciop"; String plus = cip + ciop; String build = new StringBuilder(cip).append(ciop).toString(); } 

Gera isso – veja como os dois estilos de concatenação levam ao mesmo bytecode:

  L0 LINENUMBER 23 L0 LDC "cip" ASTORE 1 L1 LINENUMBER 24 L1 LDC "ciop" ASTORE 2 // cip + ciop L2 LINENUMBER 25 L2 NEW java/lang/StringBuilder DUP ALOAD 1 INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String; INVOKESPECIAL java/lang/StringBuilder.(Ljava/lang/String;)V ALOAD 2 INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder; INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String; ASTORE 3 // new StringBuilder(cip).append(ciop).toString() L3 LINENUMBER 26 L3 NEW java/lang/StringBuilder DUP ALOAD 1 INVOKESPECIAL java/lang/StringBuilder.(Ljava/lang/String;)V ALOAD 2 INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder; INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String; ASTORE 4 L4 LINENUMBER 27 L4 RETURN 

Olhando para o exemplo acima e como o código de byte baseado no código-fonte no exemplo dado é gerado, você será capaz de perceber que o compilador transformou internamente a seguinte declaração

 cip+ciop; 

para dentro

 new StringBuilder(cip).append(ciop).toString(); 

Em outras palavras, o operador + na concatenação de strings é efetivamente um atalho para o idioma StringBuilder mais detalhado.

É o recurso de compilador Java que verifica os operandos do operador + . E com base nos operandos, gera o código de bytes:

  • Para String, gera código para sequências de concatenação
  • Para o Numbers, gera código para adicionar números.

Isto é o que a especificação Java diz :

Os operadores + e - são chamados de operadores aditivos. AdditiveExpression: MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression – MultiplicativeExpression

Os operadores aditivos têm a mesma precedência e são associativamente sintaticamente à esquerda (agrupam da esquerda para a direita). Se o tipo de operando de um operador + for String , a operação será concatenação de sequência.

Caso contrário, o tipo de cada um dos operandos do operador + deve ser um tipo que seja conversível (§5.1.8) para um tipo numérico primitivo, ou ocorre um erro em tempo de compilation.

Em todo caso, o tipo de cada um dos operandos do operador binário deve ser um tipo que seja conversível (§5.1.8) para um tipo numérico primitivo, ou ocorre um erro em tempo de compilation.

Como a class String substitui + operador?

Não faz. O compilador faz isso. Estritamente falando, o compilador sobrecarrega o operador + para os operandos String.

Primeiro de tudo (+) está sobrecarregado não substituído

A linguagem Java fornece suporte especial para o operador de concatenação de strings (+), que foi sobrecarregado para objects Java Strings.

  1. Se o operando do lado esquerdo for String, ele funcionará como concatenação.

  2. Se o operando do lado esquerdo for Integer, ele funcionará como operador de adição

A linguagem Java fornece suporte especial para o operador de concatenação de strings (+) e para conversão de outros objects em strings. A concatenação de strings é implementada através da StringBuilder (ou StringBuffer ) e seu método append .

O significado do operador + quando aplicado a String é definido pela linguagem, como todos já escreveram. Já que você não parece achar isto suficientemente convincente, considere isto:

Ints, floats e doubles têm representações binárias diferentes e, portanto, adicionar dois inteiros é uma operação diferente, em termos de manipulação de bit, do que adicionar dois floats: Para ints, você pode adicionar bit a bit, carregando um bit e verificando o estouro; para carros alegóricos, você deve lidar com as mantissas e os expoentes separadamente.

Assim, em princípio, “adição” depende da natureza dos objects que estão sendo “adicionados”. Java define para Strings, assim como ints e floats (longs, doubles, …)

O operador + é geralmente substituído por um StringBuilder em tempo de compilation. Verifique esta resposta para mais detalhes sobre esse assunto.