Tipo primitivo ‘corto’ – fundición en Java

Tengo una pregunta sobre el tipo primitivo short en Java. Estoy usando JDK 1.6.

Si tengo lo siguiente:

 short a = 2; short b = 3; short c = a + b; 

el comstackdor no quiere comstackr, dice que “no puede convertir de int a corto” y sugiere que haga un cast en short , así que esto:

 short c = (short) (a + b); 

realmente funciona Pero mi pregunta es ¿por qué necesito lanzar? Los valores de a y b están en el rango de short – el rango de valores cortos es {-32,768, 32767}. También necesito lanzar cuando quiero realizar las operaciones -, *, / (No he verificado otras).

Si hago lo mismo para primitive type int , no necesito convertir aa + bb en int . Lo siguiente funciona bien:

 int aa = 2; int bb = 3; int cc = aa +bb; 

Descubrí esto mientras diseñaba una clase en la que necesitaba agregar dos variables de tipo abreviado, y el comstackdor quería que hiciera un molde. Si hago esto con dos variables de tipo int , no necesito lanzar.

Una pequeña observación: lo mismo ocurre con el byte tipo primitivo. Entonces, esto funciona:

 byte a = 2; byte b = 3; byte c = (byte) (a + b); 

pero esto no:

 byte a = 2; byte b = 3; byte c = a + b; 

Por long , float , double e int , no hay necesidad de lanzar. Solo para valores short y de byte .

Como se explica en breve C # (pero también para otros comstackdores de lenguaje, como Java)

Hay una conversión implícita predefinida de corto a int, largo, flotante, doble o decimal.

No se pueden convertir implícitamente los tipos numéricos no literales de mayor tamaño de almacenamiento a corto (consulte la Tabla de tipos integrales para conocer los tamaños de almacenamiento de los tipos integrales). Considere, por ejemplo, las siguientes dos variables cortas xey:

 short x = 5, y = 12; 

La siguiente instrucción de asignación producirá un error de comstackción, porque la expresión aritmética en el lado derecho del operador de asignación se evalúa como int por defecto.

 short z = x + y; // Error: no conversion from int to short 

Para solucionar este problema, usa un molde:

 short z = (short)(x + y); // OK: explicit conversion 

Sin embargo, es posible utilizar las siguientes declaraciones, donde la variable de destino tiene el mismo tamaño de almacenamiento o un tamaño de almacenamiento mayor:

 int m = x + y; long n = x + y; 

Una buena pregunta de seguimiento es:

“¿por qué la expresión aritmética en el lado derecho del operador de asignación evalúa a int por defecto”?

Una primera respuesta se puede encontrar en:

Clasificando y comprobando formalmente el plegado constante de enteros

La especificación del lenguaje Java define exactamente cómo se representan los números enteros y cómo se evaluarán las expresiones aritméticas enteras . Esta es una propiedad importante de Java ya que este lenguaje de progtwigción ha sido diseñado para ser utilizado en aplicaciones distribuidas en Internet. Se requiere un progtwig Java para producir el mismo resultado independientemente de la máquina objective que lo ejecuta .

Por el contrario, C (y la mayoría de los lenguajes de progtwigción imperativos y orientados a objetos ampliamente utilizados) es más descuidado y deja abiertas muchas características importantes. La intención detrás de esta especificación de lenguaje inexacta es clara. Se supone que los mismos progtwigs C se ejecutan en una architecture de 16 bits, 32 bits o incluso 64 bits instanciando las aritméticas enteras de los progtwigs fuente con las operaciones aritméticas integradas en el procesador de destino. Esto conduce a un código mucho más eficiente porque puede usar las operaciones disponibles de la máquina directamente. Siempre que los cálculos enteros se ocupen solo de que los números sean “lo suficientemente pequeños”, no surgirán incoherencias.

En este sentido, la aritmética de enteros en C es un marcador de posición que no está definido exactamente por la especificación del lenguaje de progtwigción, pero solo se instancia completamente al determinar la máquina de destino.

Java define con precisión cómo se representan los enteros y cómo se va a calcular la aritmética de enteros.

  Java Integers -------------------------- Signed | Unsigned -------------------------- long (64-bit) | int (32-bit) | short (16-bit) | char (16-bit) byte (8-bit) | 

Char es el único tipo de entero sin signo. Sus valores representan caracteres Unicode, de \u0000 a \uffff , es decir, de 0 a 2 16 – 1.

Si un operador entero tiene un operando de tipo largo, entonces el otro operando también se convierte en tipo largo. De lo contrario, la operación se realiza en operandos de tipo int, si es necesario, los operandos más cortos se convierten en int . Las reglas de conversión están exactamente especificadas.

[De notas electrónicas en informática teórica 82 No. 2 (2003)
Blesner-Blech-COCV 2003: Sabine GLESNER , Jan Olaf BLECH,
Fakultät für Informatik,
Universität Karlsruhe
Karlsruhe, Alemania]

EDITAR: Bien, ahora sabemos que es Java …

La sección 4.2.2 de la Especificación del lenguaje Java establece:

El lenguaje de progtwigción Java proporciona una serie de operadores que actúan sobre valores integrales:

[…]

  • Los operadores numéricos, que dan como resultado un valor de tipo int o largo:
  • […]
  • Los operadores aditivos + y – (§15.18)
  • En otras palabras, es como C # – el operador de sum (cuando se aplica a tipos integrales) solo da como resultado int o long , razón por la cual necesita lanzar para asignar a una variable short .

    Respuesta original (C #)

    En C # (no ha especificado el idioma, supongo), los únicos operadores adicionales en los tipos primitivos son:

     int operator +(int x, int y); uint operator +(uint x, uint y); long operator +(long x, long y); ulong operator +(ulong x, ulong y); float operator +(float x, float y); double operator +(double x, double y); 

    Estos se encuentran en la especificación C # 3.0, sección 7.7.4. Además, se define la sum decimal:

     decimal operator +(decimal x, decimal y); 

    (La adición de enumeración, la concatenación de cadenas y la combinación de delegates también se definen allí).

    Como puede ver, no hay short operator +(short x, short y) – por lo que ambos operandos se convierten implícitamente a int, y se utiliza el formato int. Eso significa que el resultado es una expresión de tipo “int”, de ahí la necesidad de lanzar.

    En C # y Java, la expresión aritmética en el lado derecho de la tarea se evalúa a int por defecto. Es por eso que necesita volver a un breve, porque no hay una forma de conversión implícita a corta, por razones obvias.

    Dado que la pregunta “por qué int por defecto” no ha sido respondida …

    Primero, “predeterminado” no es realmente el término correcto (aunque lo suficientemente cerca). Como lo señala VonC, una expresión compuesta de enteros y largos tendrá un resultado largo. Y una operación que consta de ints / logs y dobles tendrá un doble resultado. El comstackdor promueve los términos de una expresión para cualquier tipo que proporcione un mayor rango y / o precisión en el resultado (se supone que los tipos de coma flotante tienen mayor rango y precisión que la integral, aunque se pierde precisión convirtiendo largos largos en dobles).

    Una advertencia es que esta promoción solo ocurre por los términos que la necesitan. Entonces, en el siguiente ejemplo, la subexpresión 5/4 usa solo valores integrales y se realiza usando matemáticas enteras, aunque la expresión general involucra un doble. El resultado no es lo que podrías esperar …

     (5/4) * 1000.0 

    OK, entonces ¿por qué byte y short son promocionados a int? Sin ninguna referencia para respaldarme, se debe a la practicidad: hay un número limitado de códigos de bytes.

    “Bytecode”, como su nombre lo indica, usa un solo byte para especificar una operación. Por ejemplo, iadd , que agrega dos ints. Actualmente, se definen 205 códigos de operación , y la matemática entera toma 18 para cada tipo (es decir, un total de 36 entre entero y largo), sin contar los operadores de conversión.

    Si es corto, y byte cada uno tiene su propio conjunto de códigos de operación, estaría en 241, lo que limita la capacidad de expansión de la JVM. Como dije, no hay referencias que me respalden en esto, pero sospecho que Gosling et al dijeron “¿con qué frecuencia la gente usa los pantalones cortos?” Por otro lado, promover byte a int lleva a este efecto no tan maravilloso (la respuesta esperada es 96, el real es -16):

     byte x = (byte)0xC0; System.out.println(x >> 2); 

    Qué idioma estás usando?

    Muchos lenguajes basados ​​en C tienen una regla de que cualquier expresión matemática se realiza en tamaño int o mayor. Debido a esto, una vez que agrega dos cortos el resultado es de tipo int. Esto causa la necesidad de un yeso.

    Java siempre usa al menos 32 valores de bit para los cálculos. Esto se debe a la architecture de 32 bits que era común en 1995 cuando se introdujo Java. El tamaño del registro en la CPU era de 32 bits y la unidad lógica aritmética aceptaba 2 números de la longitud de un registro de la CPU. Entonces la CPU se optimizó para tales valores.

    Esta es la razón por la cual todos los tipos de datos que admiten operaciones aritméticas y tienen menos de 32 bits se convierten en int (32 bit) tan pronto como los utiliza para los cálculos.

    Por lo tanto, resumirlo se debe principalmente a problemas de rendimiento y se mantiene hoy en día para compatibilidad.

    En java, cada expresión numérica como:

     anyPrimitive zas = 1; anyPrimitive bar = 3; ?? x = zas + bar 

    x siempre resultará ser al menos un int, o un long si uno de los elementos de sum fue largo.

    Pero hay algunos caprichos difíciles

     byte a = 1; // 1 is an int, but it won't compile if you use a variable a += 2; // the shortcut works even when 2 is an int a++; // the post and pre increment operator work 

    AFAIS, nadie menciona el uso final para eso. Si modifica su último ejemplo y define las variables a y b como variables final , entonces el comstackdor tiene la seguridad de que su sum, el valor 5, puede asignarse a una variable de tipo byte , sin pérdida de precisión. En este caso, el comstackdor es bueno para asignar la sum de ayb a c. Aquí está el código modificado:

     final byte a = 2; final byte b = 3; byte c = a + b; 

    Cualquier tipo de datos que sea inferior a “int” (excepto booleano) se convierte implícitamente a “int”.

    En tu caso:

     short a = 2; short b = 3; short c = a + b; 

    El resultado de (a + b) se convierte implícitamente a int. Y ahora lo está asignando a “corto”. Por lo tanto, está obteniendo el error.

    short, byte, char –para todos estos obtendremos el mismo error.

    Me gustaría agregar algo que no se haya señalado. Java no tiene en cuenta los valores que le ha dado a las variables (2 y 3) en …

    corto a = 2; short b = 3; short c = a + b;

    Entonces, por lo que Java sabe, podrías hacer esto …

    abreviado a = 32767; short b = 32767; short c = a + b;

    Que estaría fuera del rango de corto, autoboxes el resultado a un int porque es “posible” que el resultado será más que un corto, pero no más que un int. Int fue elegido como “predeterminado” porque básicamente la mayoría de la gente no tendrá valores de encoding difíciles por encima de 2,147,483,647 o por debajo de -2,147,483,648