Ampliación de Byte a Int (bicho Marshmallow)

Lo siento de antemano por la larga pregunta, pero todo debe ser sencillo y claro lo que está pasando, gracias por echar un vistazo. Tenga en cuenta que esto no es realmente código, sólo pseudo código para entender la aplicación de la aplicación.

Problema

Los bytes no se ensanchan al valor numérico verdadero. Nota: level = -1 representa un juego que no ha comenzado. level == 24 representa el final del juego.

Clase 1

 private byte level = -1; private byte stage = 0; @NonNull private final Stages[][] stages = new Stages[25][13]; public byte getLevel () { return level; } public void nextLevel () { // expect: 0 level++; // stages[ 128][ 0] (ArrayIndexOutOfBounds) stages[level][stage] = new Stage(); } 

La Clase 2 amplía la Clase 1

 @NonNull private final byte[][] values = new byte[25][4]; public byte getScore (final byte level, final byte player) { // values[ 255][ 2] (ArrayIndexOutOfBounds) return values[level][player]; } // expecting: -1 >= 0 (false) // runtime: 255 >= 0 (true) if (Class1.getLevel() >= 0) getScore(Class1.getLevel(), 2); 

Binario

8 bits (byte)

 -1 == 1111 1111 -128 == 1000 0000 127 == 0111 1111 

32 bits (entero)

 -1 == 1111 1111 1111 1111 1111 1111 1111 1111 127 == 0000 0000 0000 0000 0000 0000 0111 1111 128 == 0000 0000 0000 0000 0000 0000 1000 0000 255 == 0000 0000 0000 0000 0000 0000 1111 1111 

Lo que trabajó

Uso de la clase wrapper

 public Byte level = -1; 

Pregunta

Entiendo que el problema es la representación binaria del número se utiliza directamente cuando se ensancha de byte a int. Mi número va literalmente de 8 bits 1111 1111 a 32 bits 0000 0000 0000 0000 0000 0000 1111 1111 . Mi pregunta es por qué no Java (o por qué no es en esta situación / entorno) convertir el número en el valor numérico verdadero al ensancharse en lugar de sólo rellenar ceros a la representación binaria en bruto.

Esto parece estar ocurriendo sólo a números negativos, supongo que los números positivos tienen la misma representación de bits antes y después del ensanchamiento.

¿Por qué mi número no va de 8 bits 1111 1111 a 32 bits 1111 1111 1111 1111 1111 1111 1111 1111 ? ¿Por qué el incremento de postfix crea un valor de 128 ..? ¿Hay una mejor solución a este problema al lado de la que actualmente estoy atrapado.?

Yo prefiero no sólo usar esa solución sin conocer el problema de subrayado porque el problema puede silencio (ejecutar sin errores) romper mi algoritmo de aplicaciones; Así que es con mucho aprecio si alguien puede por favor explicar este tema para mí.

Gracias, Jay

Ambiente de trabajo actual

JDK 1.8.076

OS X El Capitán

Android Studio 2.2 Vista previa 2

BuildToolsVersion '23 .0.3 '

Classpath 'com.android.tools.build:gradle:2.2.0-alpha2'

Emulador Nexus 6P API 23 x86

Conclusión

Pude restringir el problema exclusivamente a los dispositivos Android 23 (Marshmallow). He informado sobre el error a Google Inc. Gracias por la ayuda de todos, sólo voy a dar una advertencia a Android 23 (Marshmallow) de los usuarios como el error no aparece en Android N, Android 22 y menor.

¿Por qué no traducir los bytes firmados a unsigned?

 public static int signedByteToInt(byte b) { return b & 0xFF; } 

Para asegurarse de que aquí hay muestras de representación en byte firmado:

 -3 - 11111101 -2 - 11111110 -1 - 11111111 0 - 00000000 1 - 00000001 2 - 00000010 3 - 00000011 

Y cuando se utiliza byte como int que java de todos modos representará este byte como firmado por lo que desde 11111111 (-1) obtendrá 11111111 11111111 11111111 11111111 (-1) y no veo aquí ningún problema.

Solo recuerda que:

 from -1 to -128 is from 11111111 to 10000000 and from 0 to 127 is from 00000000 to 01111111 

Y hacer la conversión adecuada cuando se utiliza como int.

Por lo que las representaciones por debajo de cero son como hacia atrás contra el medio

Y por la forma en que esto no es sólo en java)

aquí:

 if (Class1.getLevel() >= 0) 

Usted compara el byte con entero, intenta hacer:

 if (Class1.getLevel() >= (byte)0) 

Y sentirse feliz

Jay, vi tu código y revisé la documentación del lenguaje Java.

Para mí, el comportamiento que usted describe es el siguiente:

 private byte level = -1; private byte stage = 0; 

Inicializa los bytes en -1 y 0. Más tarde, llama a nextLevel() y espera que init stage[0][0] , pero en su lugar, recibe una excepción "fuera de límites". Por lo tanto, el primer nivel nunca se alcanza.

 public void nextLevel() { // expect: 0 level++; // stages[ 128][ 0] (ArrayIndexOutOfBounds) stages[level][stage] = new Stage(); } 

Si el código que no mostró en su muestra no crea efectos secundarios que producen la situación, el siguiente código es una muestra de trabajo, que debería ser suficiente para exponer el problema:

 package com.bytemagic; import com.sun.istack.internal.NotNull; /** * Created by thst on 01.06.2016. */ public class ByteMagic { private class Stage { } private byte level = -1; private byte stage = 0; @NotNull private final Stage[][] stages = new Stage[25][13]; public byte getLevel() { return level; } public void nextLevel() { // expect: 0 level++; // stages[ 128][ 0] (ArrayIndexOutOfBounds) stages[level][stage] = new Stage(); } public static void main(String... args) { ByteMagic me = new ByteMagic(); me.nextLevel(); System.out.println(Integer.toHexString(me.getLevel())); } } 

He intentado este código con JDK8u66, JDK8u77. Esto no expone ningún problema. El level byte se incrementará correctamente a 0 y las stages se están inicializando correctamente.

¿Podría por favor intentar ejecutar ese código en su máquina y configuración? ¿Está este código exponiendo el problema?

Después de todo: level no puede contener 128, puede contener -128, pero eso no es lo que usted describe.

level++ hará todo tipo de conversiones divertidas. De acuerdo con los documentos, para calcular el incremento, 1 , el level se convierte en entero con el ensanchamiento adecuado si es necesario (así que 0xff -> 0xffffffff), entonces se agrega 1, resultando en 0x0 (int). Esto se vuelve a reducir a 0x0 (byte) y se escribe a level . ( https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.2 )

El acceso a la matriz está utilizando una regla de conversión ligeramente diferente. El acceso a la matriz requiere que el índice sea del tipo integer. La conversión de byte a int usa reglas de promoción numéricas unary, que pueden tener un efecto de conversión interesante cuando se utiliza unary menos, pero para tu caso, con un valor de byte de 0 , nada espectacular o inesperado sucederá.

(Para referencia: https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.6.1 y https://docs.oracle.com/javase/specs/ Jls / se8 / html / jls-10.html # jls-10.4 y https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.10.3 )

Por lo tanto, no puedo reproducir el error con los ejemplos de código dado, y mi sospecha va en la dirección de que esto es o bien algún efecto secundario de código que no puedo ver o es un error en el JDK que utiliza o en el entorno (Dalvik VM) .

  • OnRequestPermissionsResult no se llama en fragmento si se define tanto en el fragmento y la actividad
  • Wakelock y modo doze
  • ¿Cuánto tiempo tarda para que android pase al modo doze?
  • ¿Cómo inhabilitar una aplicación del modo Doze?
  • Acceso a la red en modo doze
  • Aplicación personalizada no creada en Android M (vista previa final)
  • SMSMessage createFromPdu con formato de parámetro adicional
  • Ni el usuario 10102 ni el proceso actual tienen android.permission.READ_PHONE_STATE
  • Control de linterna en Marshmallow
  • Doze, diferente entre Marshmallow y Nougat
  • Android 23 No genera el archivo de manifiesto para usos-elementos de permiso
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.