从字节扩展到Int(Marshmallow bug)

Jay*_*ris 5 android android-6.0-marshmallow

对于这个长期问题提前抱歉,但一切都应该是直截了当的,并清楚发生了什么,谢谢你看看.请注意,这实际上不是代码,只是伪代码来理解应用程序的实现.

问题

字节不会扩大到真正的数值.注意:level = -1表示尚未开始的游戏.level == 24代表游戏的结束.

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();
}
Run Code Online (Sandbox Code Playgroud)

第2类扩展第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);
Run Code Online (Sandbox Code Playgroud)

二进制

8位(字节)

-1   == 1111 1111
-128 == 1000 0000
 127 == 0111 1111
Run Code Online (Sandbox Code Playgroud)

32位(整数)

-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
Run Code Online (Sandbox Code Playgroud)

做了什么

使用包装类

public Byte level = -1;
Run Code Online (Sandbox Code Playgroud)

我理解问题是数字的二进制表示在从byte扩展到int时直接使用.我的数字实际上是从8位1111 1111到32位0000 0000 0000 0000 0000 0000 1111 1111.我的问题是为什么Java(或者为什么不在这种情况/环境中)在扩展时将数字转换为真正的数值而不是仅仅将填充零填充到原始二进制表示.

这似乎只发生在负数上,我假设因为正数在加宽之前和之后具有相同的位表示.

为什么我的号码从8位1111 1111变为32位1111 1111 1111 1111 1111 1111 1111 1111?为什么后缀增量创建值为128 ..?除了我目前坚持使用的问题之外,还有更好的解决方案吗?

我不想在不知道下划线问题的情况下使用该解决方案,因为问题可以安静地运行(无错运行)破坏我的应用程序算法; 如果有人可以向我解释这个问题,我们非常感激.

谢谢,杰伊

当前的工作环境

JDK 1.8.076

OS X El Capitan

Android Studio 2.2预览版2

buildToolsVersion '23 .0.3'

classpath'com.android.tools.build:grad:2.2.0-alpha2'

仿真器 Nexus 6P API 23 x86

结论

我能够将问题缩小到专门的Android 23(Marshmallow)设备.我已向谷歌公司报告了这个错误.感谢大家的帮助,我只会向Android 23(Marshmallow)用户发出警告,因为该错误未出现在Android N,Android 22及更低版本中.

Ste*_*mov 3

为什么不将有符号字节转换为无符号字节?

public static int signedByteToInt(byte b) {
    return b & 0xFF;
}
Run Code Online (Sandbox Code Playgroud)

为了确保您这里是有符号字节的表示示例:

-3 - 11111101
-2 - 11111110
-1 - 11111111
0  - 00000000
1  - 00000001
2  - 00000010
3  - 00000011
Run Code Online (Sandbox Code Playgroud)

当你使用 byte 作为 int 时,java无论如何都会将该字节表示为有符号的字节,因此从 11111111 (-1) 开始,你将得到 11111111 11111111 11111111 11111111 (-1),我在这里没有看到任何问题。

只要记住:

from -1 to -128 is from 11111111 to 10000000
and from 0 to 127 is from 00000000 to 01111111
Run Code Online (Sandbox Code Playgroud)

并在将其用作 int 时进行正确的转换。

所以低于零的表示就像向后逆向中间

顺便说一句,这不仅在 java 中)

这里:

if (Class1.getLevel() >= 0)
Run Code Online (Sandbox Code Playgroud)

您将字节与整数进行比较,尝试进行:

if (Class1.getLevel() >= (byte)0)
Run Code Online (Sandbox Code Playgroud)

并感到快乐:)