Java: ¿por qué recibo el mensaje de error “Tipo de discrepancia: no se puede convertir int en byte”

Si declara variables de tipo byte o corto e intenta realizar operaciones aritméticas en ellas, recibirá el error “No coinciden los tipos: no puede convertir int a corto” (o correspondientemente “Tipo no coincidente: no se puede convertir int en byte”).

byte a = 23; byte b = 34; byte c = a + b; 

En este ejemplo, el error de comstackción está en la tercera línea.

Aunque los operadores aritméticos están definidos para operar en cualquier tipo numérico, de acuerdo con la especificación del lenguaje Java (5.6.2 Promoción Numérica Binaria), los operandos de tipo byte y corto se promueven automáticamente a int antes de ser entregados a los operadores.

Para realizar operaciones aritméticas en variables de tipo byte o corto, debe encerrar la expresión entre paréntesis (dentro de las cuales las operaciones se llevarán a cabo como tipo int), y luego devolver el resultado al tipo deseado.

  byte a = 23;
 byte b = 34;
 byte c = (byte) (a + b); 

Aquí hay una pregunta de seguimiento para los gurús reales de Java: ¿por qué? Los tipos byte y short son tipos numéricos perfectamente precisos. ¿Por qué Java no permite operaciones aritméticas directas en estos tipos? (La respuesta no es “pérdida de precisión”, ya que no hay ninguna razón aparente para convertir a int en primer lugar).

Actualización: jrudolph sugiere que este comportamiento se basa en las operaciones disponibles en la JVM, específicamente, que solo se implementan operadores de palabra completa y de doble palabra. Por lo tanto, para el operador en bytes y cortos, se deben convertir a int.

La respuesta a su pregunta de seguimiento está aquí:

los operandos de tipo byte y short se promueven automáticamente a int antes de ser entregados a los operadores

Entonces, en su ejemplo, a y b se convierten ambos a int antes de ser entregados al operador +. El resultado de agregar dos int s juntos también es un int . Al intentar asignar ese valor int a un byte , se produce el error porque hay una posible pérdida de precisión. Al emitir explícitamente el resultado, le está diciendo al comstackdor “Sé lo que estoy haciendo”.

Creo que el asunto es que la JVM solo admite dos tipos de valores de stack: tamaño de palabra y tamaño de palabra doble.

Entonces probablemente decidieron que necesitarían solo una operación que funcione en enteros de tamaño de palabra en la stack. Por lo tanto, solo hay iadd, imul, etc. en el nivel de código de bytes (y no hay operadores para bytes y cortos).

Por lo tanto, obtiene un valor int como resultado de estas operaciones, que Java no puede convertir de manera segura a los tipos de datos de byte más pequeños y cortos. Entonces te obligan a lanzar para reducir el valor de nuevo a byte / corto.

Pero al final tienes razón: este comportamiento no es consistente con el comportamiento de los ints, por ejemplo. Puede sin problemas agregar dos entradas y no obtener ningún error si el resultado se desborda.

El lenguaje Java siempre promueve argumentos de operadores aritméticos a int, long, float o double. Entonces toma la expresión:

 a + b 

donde a y b son de tipo byte. Esto es una abreviatura de:

 (int)a + (int)b 

Esta expresión es de tipo int. Claramente tiene sentido dar un error al asignar un valor int a una variable de byte.

¿Por qué el lenguaje se definiría de esta manera? Supongamos que a era 60 yb era 70, entonces a + b es -126 – desbordamiento entero. Como parte de una expresión más complicada que se espera que dé como resultado un int, esto puede convertirse en un error difícil. Restrinja el uso de byte y corto a almacenamiento en matriz, constantes para formatos de archivo / protocolos de red y rompecabezas.

Hay una grabación interesante de JavaPolis 2007. James Gosling está dando un ejemplo sobre lo complicada que es la aritmética sin signo (y por qué no está en Java). Josh Bloch señala que su ejemplo da el ejemplo incorrecto bajo la aritmética normal firmada también. Para una aritmética comprensible, necesitamos precisión arbitraria.