¿Cómo anula la clase String el operador +?
¿Por qué en Java puedes agregar cadenas con el operador +, cuando String es una clase? En el String.java
código no encontré ninguna implementación para este operador. ¿Este concepto viola la orientación a objetos?
Veamos las siguientes expresiones simples en Java.
int x=15;
String temp="x = "+x;
El compilador "x = "+x;
lo convierte StringBuilder
internamente 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 StringBuilder
modismo más detallado.
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 - MultiplicativeExpressionLos 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 esString
, 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.
¿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.