En Java, ¿el resultado de la adición de dos caracteres es un int o un char?

81

Cuando se agrega 'a' + 'b'produce 195. ¿Es el tipo de datos de salida charo int?

naranja
fuente
3
Si el tipo fuera char, el valor de 'a' + 'b'no sería 195pero'Ã'
Joren
1
Es 195 aquí - ideone.com pero no en Eclipse.
naranja
2
¡Leíste eso del libro de Algoritmos lol! Vine aquí exactamente por este ejercicio;)
Jack Twain

Respuestas:

133

El resultado de agregar caracteres, cortos o bytes de Java es un int :

Especificación del lenguaje Java sobre promoción numérica binaria :

  • Si alguno de los operandos es de un tipo de referencia, se realiza la conversión de unboxing (§5.1.8). Luego:
  • Si alguno de los operandos es de tipo double, el otro se convierte en double.
  • De lo contrario, si alguno de los operandos es de tipo flotante, el otro se convierte en flotante.
  • De lo contrario, si alguno de los operandos es de tipo long, el otro se convierte en long.
  • De lo contrario, ambos operandos se convierten al tipo int.

Pero tenga en cuenta lo que dice sobre los operadores de asignación compuesta (como + =) :

El resultado de la operación binaria se convierte al tipo de la variable de la izquierda ... y el resultado de la conversión se almacena en la variable.

Por ejemplo:

char x = 1, y = 2;
x = x + y; // compile error: "possible loss of precision (found int, required char)"
x = (char)(x + y); // explicit cast back to char; OK
x += y; // compound operation-assignment; also OK

Una forma de averiguar el tipo de resultado, en general, es lanzarlo a un Objeto y preguntarle de qué clase es:

System.out.println(((Object)('a' + 'b')).getClass());
// outputs: class java.lang.Integer

Si está interesado en el rendimiento, tenga en cuenta que el código de bytes de Java ni siquiera tiene instrucciones dedicadas para aritmética con los tipos de datos más pequeños. Por ejemplo, para sumar, hay instrucciones iadd(para ints), ladd(para largos), fadd(para flotadores), dadd(para dobles), y eso es todo. Para simular x += ycon los tipos más pequeños, el compilador usará iaddy luego pondrá a cero los bytes superiores del int usando una instrucción como i2c("int to char"). Si la CPU nativa tiene instrucciones dedicadas para datos de 1 byte o 2 bytes, depende de la máquina virtual Java optimizarlas en tiempo de ejecución.

Si desea concatenar caracteres como una cadena en lugar de interpretarlos como un tipo numérico, hay muchas formas de hacerlo. Lo más fácil es agregar una cadena vacía a la expresión, porque agregar un carácter y una cadena da como resultado una cadena. Todas estas expresiones dan como resultado la Cadena "ab":

  • 'a' + "" + 'b'
  • "" + 'a' + 'b'(esto funciona porque "" + 'a'se evalúa primero; si ""estuvieran al final, obtendría "195")
  • new String(new char[] { 'a', 'b' })
  • new StringBuilder().append('a').append('b').toString()
  • String.format("%c%c", 'a', 'b')
Boann
fuente
22

Las operaciones aritméticas binarias en chary byte(y short) promueven a int- JLS 5.6.2.

Lamidas calientes
fuente
2
Y operaciones aritméticas unarias.
Tom Hawtin - tackline
7

Es posible que desee aprender las siguientes expresiones sobre char.

char c='A';
int i=c+1;

System.out.println("i = "+i);

Esto es perfectamente válido en Java y devuelve 66, el valor correspondiente del carácter (Unicode) de c+1.


String temp="";
temp+=c;
System.out.println("temp = "+temp);

Esto es demasiado válido en Java y la variable de tipo String tempacepta automáticamente el ctipo char y produce temp=Aen la consola.


¡Todas las siguientes declaraciones también son válidas en Java!

Integer intType=new Integer(c);
System.out.println("intType = "+intType);

Double  doubleType=new Double(c);
System.out.println("doubleType = "+doubleType);

Float floatType=new Float(c);
System.out.println("floatType = "+floatType);

BigDecimal decimalType=new BigDecimal(c);
System.out.println("decimalType = "+decimalType);

Long longType=new Long(c);
System.out.println("longType = "+longType);

Aunque ces un tipo de char, se puede suministrar sin errores en los constructores respectivos y todas las declaraciones anteriores se tratan como declaraciones válidas. Producen las siguientes salidas respectivamente.

intType = 65
doubleType = 65.0
floatType = 65.0
decimalType = 65
longType =65

chares un tipo integral numérico primitivo y, como tal, está sujeto a todas las reglas de estas bestias, incluidas las conversiones y promociones. Querrá leer más sobre esto, y JLS es una de las mejores fuentes para esto: conversiones y promociones . En particular, lea el breve fragmento sobre "5.1.2 Ampliación de la conversión primitiva".

León
fuente
3

El compilador de Java puede interpretarlo como cualquiera.

Compruébelo escribiendo un programa y buscando errores del compilador:

public static void main(String[] args) {
    int result1 = 'a' + 'b';
    char result2 = 'a' + 'b';
}

Si es un carácter, entonces la primera línea me dará un error y la segunda no. Si es un int, entonces sucederá lo contrario.

Lo compilé y obtuve ..... NO ERRORES. Entonces Java acepta ambos.

Sin embargo, cuando los imprimí, obtuve:

int: 195

char: Ã

Lo que pasa es que cuando lo haces:

char result2 = 'a' + 'b'

se realiza una conversión implícita (una "conversión de restricción primitiva" de int a char ).

eboix
fuente
Me sorprende que no haya recibido una advertencia del compilador en el segundo caso sobre una posible pérdida de precisión debido al estrechamiento.
Hot Licks
@eboix: usted escribió "el compilador pone automáticamente a carbón o int" [sic] ... Lo cual no es correcto porque un int no está "fundido" a un int y viniendo de un int a un carbón no se llama una "conversión" pero una "conversión primitiva de reducción"; )
TacticalCoder
Si. Yo también esperaba eso. De hecho, había escrito parte de mi respuesta sobre eso antes de crear mi programa, pero luego lo eliminé una vez que vi que no recibía advertencias ni errores.
eboix
@eboix: eh eh :) Lo habría editado pero todavía no tengo 2000 puntos de reputación, de ahí mi comentario en lugar de una edición; )
TacticalCoder
Si quieres, @ user988052, puedo volver a cambiarlo a lo que era y puedes editarlo, obteniendo puntos. Aún puede editarlo si tiene menos de 2000 puntos de reputación. Lo único es que la persona que hizo la publicación tiene que aceptar la edición. Lo volveré a cambiar ahora mismo para que puedas obtener los dos puntos que te pertenecen por derecho.
eboix
1

De acuerdo con las reglas de promoción binaria , si ninguno de los operandos es double, float o long, ambos se promocionan a int. Sin embargo, recomiendo encarecidamente no tratar el tipo char como numérico, ya que eso frustra su propósito.

Sergei Tachenov
fuente
1
El uso charcomo valor numérico está completamente dentro de su propósito, por lo que JLS dedica tanta verborrea a dicho uso.
Lew Bloch
1

Si bien ya tiene la respuesta correcta (a la que se hace referencia en el JLS), aquí hay un poco de código para verificar que obtiene un intal agregar dos chars.

public class CharAdditionTest
{
    public static void main(String args[])
    {
        char a = 'a';
        char b = 'b';

        Object obj = a + b;
        System.out.println(obj.getClass().getName());
    }
}

La salida es

java.lang.Integer

Pablo
fuente
Esta no es una verificación convincente, porque ha incluido una conversión de boxeo en la mezcla. Los tipos inty Integerno son lo mismo. Una verificación más convincente es intentar asignar a + ba una intvariable o una charvariable. Este último da un error de compilación que dice en efecto "no se puede asignar una inta una char".
Stephen C
0

charse representa como Unicodevalores y donde los valores Unicode se representan \useguido de Hexadecimalvalores.

Como cualquier operación aritmética sobre charvalores promovidos int, el resultado de 'a' + 'b'se calcula como

1.) Aplicar los Unicodevalores en el charuso correspondienteUnicode Table

2.) Aplicar la conversión de hexadecimal a decimal y luego realizar la operación en Decimalvalores.

    char        Unicode      Decimal
     a           0061          97
     b           0062          98  +
                              195

Unicode To Decimal Converter

Ejemplo

0061

(0 * 16 3 ) + (0 * 16 2 ) + (6 * 16 1 ) + (1 * 16 0 )

(0 * 4096) + (0 * 256) + (6 * 16) + (1 * 1)

0 + 0 + 96 + 1 = 97

0062

(0 * 16 3 ) + (0 * 16 2 ) + (6 * 16 1 ) + (2 * 16 0 )

(0 * 4096) + (0 * 256) + (6 * 16) + (2 * 1)

0 + 0 + 96 + 2 = 98

Por lo tanto 97 + 98 = 195


Ejemplo 2

char        Unicode      Decimal
 Ջ           054b         1355
 À           00c0          192 
                      --------
                          1547    +
                          1163    -
                             7    /
                        260160    *
                            11    %
Pavneet_Singh
fuente
Esto no es sobre lo que se pregunta la pregunta.
Stephen C
Para su información, mi respuesta detallada al comentario anterior ha sido eliminada por modificaciones que explicaban el motivo de la migración de mi respuesta de una publicación eliminada. Si mi respuesta ha sido eliminada para encubrir las fallas de la moderación SO, ¿puede al menos eliminar el comentario anterior o indicar la audiencia de alguna manera para que no tenga que escribir otro comentario? preguntas a los mods SO
Pavneet_Singh
Mantengo mi comentario. Como le respondí ... pero luego eliminé ... la razón por la que publicó esta Pregunta aquí no cambia el hecho de que está un 95% fuera del tema de la pregunta y un 5% de repetición de las respuestas anteriores. Si desea guardar los resultados de su esfuerzo desperdiciado, sería más apropiado guardarlo en su disco duro. O busque alguna otra pregunta que sea relevante.
Stephen C
Si tiene alguna queja con los moderadores, consúltela en meta.stackoverflow.com. Y proporcione pruebas. Todo lo que estoy tratando de hacer aquí es ordenar >> estas << Preguntas y Respuestas.
Stephen C
Entiendo su punto de vista, pero no puedo entender el hecho de ignorar los detalles de la conversión Unicode con ejemplos, como un valor adicional que podría ayudar a algunos lectores, así que me gustaría mantener esta respuesta (entiendo que no es útil para usted y parece fuera de lugar) tema). Evito los lugares meta y similares, ya que no es fácil hacer esas cosas sin poder o apoyo, lo que requiere mucho tiempo y esfuerzo. Prefiero mantener mi paz interior Sire.
Pavneet_Singh
0

Si bien la respuesta de Boann es correcta, existe una complicación que se aplica al caso de las expresiones constantes cuando aparecen en contextos de asignación .

Considere los siguientes ejemplos:

  char x = 'a' + 'b';   // OK

  char y = 'a';
  char z = y + 'b';     // Compilation error

Que esta pasando? Quieren decir lo mismo, ¿no? ¿Y por qué es legal asignar un inta charen el primer ejemplo?

Cuando aparece una expresión constante en un contexto de asignación, el compilador de Java calcula el valor de la expresión y ve si está en el rango del tipo al que está asignando. Si es así, se aplica una conversión primitiva de restricción implícita .

  • En el primer ejemplo, 'a' + 'b'es una expresión constante, y su valor cabrá en a char, por lo que el compilador permite el estrechamiento implícito del intresultado de la expresión a a char.

  • En el segundo ejemplo, yes una variable, por y + 'b'lo que NO es una expresión constante. Entonces, aunque Blind Freddy puede ver que el valor encaja, el compilador NO permite ningún estrechamiento implícito y obtiene un error de compilación que dice que intno se puede asignar un valor a char.

Hay algunas otras advertencias sobre cuándo se permite una conversión primitiva de restricción implícita en este contexto; consulte JLS 5.2 y JLS 15.28 para conocer todos los detalles.

Este último explica en detalle los requisitos para una expresión constante . Puede que no sea lo que piensas. (Por ejemplo, simplemente declarar ycomo finalno ayuda).

Stephen C
fuente