¿Cómo anula la clase String el operador +?

Resuelto Pooya asked hace 12 años • 7 respuestas

¿Por qué en Java puedes agregar cadenas con el operador +, cuando String es una clase? En el String.javacódigo no encontré ninguna implementación para este operador. ¿Este concepto viola la orientación a objetos?

Pooya avatar Jul 10 '12 14:07 Pooya
Aceptado

Veamos las siguientes expresiones simples en Java.

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

El compilador "x = "+x;lo convierte StringBuilderinternamente y lo utiliza .append(int)para "agregar" el número entero a la cadena.

5.1.11. Conversión de cadenas

Cualquier tipo puede convertirse al tipo String mediante conversión de cadena.

Un valor x de tipo primitivo T se convierte primero en un valor de referencia como si se lo diera como argumento a una expresión de creación de instancia de clase apropiada (§15.9):

  • Si T es booleano, utilice el nuevo booleano (x).
  • Si T es char, entonces use el nuevo carácter (x).
  • Si T es byte, short o int, utilice el nuevo Integer(x).
  • Si T es largo, utilice el nuevo Long(x).
  • Si T es flotante, utilice el nuevo Flotador (x).
  • Si T es doble, utilice el nuevo Doble (x).

Este valor de referencia luego se convierte al tipo String mediante conversión de cadena.

Ahora sólo es necesario considerar los valores de referencia:

  • Si la referencia es nula, se convierte en la cadena "nula" (cuatro caracteres ASCII n, u, l, l).
  • De lo contrario, la conversión se realiza como mediante una invocación del método toString del objeto referenciado sin argumentos; pero si el resultado de invocar el método toString es nulo, entonces se utiliza la cadena "null".

El método toString está definido por la clase primordial Objeto (§4.3.2). Muchas clases lo anulan, en particular booleana, carácter, entero, largo, flotante, doble y cadena.

Consulte §5.4 para obtener detalles sobre el contexto de conversión de cadenas.

15.18.1.

Optimización de la concatenación de cadenas: una implementación puede optar por realizar la conversión y la concatenación en un solo paso para evitar crear y luego descartar un objeto String intermedio. Para aumentar el rendimiento de la concatenación de cadenas repetidas, un compilador de Java puede utilizar la clase StringBuffer o una técnica similar para reducir el número de objetos String intermedios que se crean mediante la evaluación de una expresión.

Para tipos primitivos, una implementación también puede optimizar la creación de un objeto contenedor al convertir directamente de un tipo primitivo a una cadena.

La versión optimizada en realidad no realizará primero una conversión de cadena completa.

Esta es una buena ilustración de una versión optimizada utilizada por el compilador, aunque sin la conversión de una primitiva, donde puedes ver al compilador cambiando cosas a StringBuilder en 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();
}

Genera esto: vea cómo los dos estilos de concatenación conducen al mismo código de bytes:

 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.<init>(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.<init>(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

Si observa el ejemplo anterior y cómo se genera el código de bytes basado en el código fuente del ejemplo dado, podrá notar que el compilador ha transformado internamente la siguiente declaración

cip+ciop; 

en

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

En otras palabras, el operador +en la concatenación de cadenas es efectivamente una abreviatura del StringBuildermodismo más detallado.

Lion avatar Jul 10 '2012 07:07 Lion

Es una característica del compilador de Java que verifica los operandos del +operador. Y en base a los operandos genera el código de bytes:

  • Para String, genera código para concatizar cadenas.
  • Para Números, genera código para sumar números.

Esto es lo que dice la especificación de Java :

Los operadores + y -se denominan operadores aditivos. AdditiveExpression: MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression - MultiplicativeExpression

Los operadores aditivos tienen la misma precedencia y son sintácticamente asociativos por izquierda (se agrupan de izquierda a derecha). Si el tipo de cualquiera de los operandos de un +operador es String, entonces la operación es una concatenación de cadenas.

De lo contrario, el tipo de cada uno de los operandos del +operador debe ser un tipo convertible (§5.1.8) a un tipo numérico primitivo, o se producirá un error en tiempo de compilación.

En todos los casos, el tipo de cada uno de los operandos del -operador binario debe ser un tipo convertible (§5.1.8) a un tipo numérico primitivo, o se producirá un error en tiempo de compilación.

Ramesh PVK avatar Jul 10 '2012 07:07 Ramesh PVK

¿Cómo la clase String anula el operador +?

No es así. El compilador lo hace. Estrictamente hablando, el compilador sobrecarga el operador + para operandos de cadena.

user207421 avatar Jul 10 '2012 09:07 user207421