【问题标题】:Is Byte implemented as Int anyway?Byte 无论如何都实现为 Int 吗?
【发布时间】:2013-09-29 13:53:57
【问题描述】:

我有一本 java 游戏书建议尽可能将所有数据实现为 Int,该类型运行速度最快。它说 Byte、Char 和 Boolean 无论如何都是作为 Int 实现的,因此您不会节省空间,并且由于 Byte 数据而最终不得不在代码中进行的转换会减慢它的速度。例如,

需要一个演员表

a = (字节)(b+c);

由于加法结果是 Int,即使 a、b 和 c 都声明为 Bytes。

我目前有一个巨大的 2D 数组声明为我的游戏的字节,以节省空间和按位运算。真的是节省空间吗?我还在示例中看到了对 Ints 进行的按位运算,按位运算在 Ints 上是否按预期工作?

【问题讨论】:

  • 那是什么书?听起来像一个可怕的一个
  • 你能说出(“羞耻”)这本书的名字吗?我很想看看它还有什么像这样的小宝石。我的猜测是,这是一种混乱的理解……在堆栈上或在布置类的数据结构时; JVM可能选择将字节变量填充到 4 个字节。即使在 C 语言下,这也是一种常见的优化。但你永远不能确定编译器/JVM 会这样做。存在优化是因为 some 架构上的 1 字节读取是 4 字节读取,然后是掩码/位移。
  • 其实这是一本“傻瓜”的书,通常很可靠。提高代码效率的“10 年代的一部分”十个技巧之一。
  • @michael 这本书什么时候出版的?或者它涵盖什么版本的 Java?
  • @couling 实际上,byte 类型的填充变量是 JLS 在单个变量的情况下强制要求的(数组不是这样)。查看我对链接的回答。

标签: java int byte


【解决方案1】:

这通常是不正确的。其实这在JVM Specification §2.3中有概述:

Java 虚拟机支持的原始数据类型是数字类型、boolean 类型 (§2.3.4) 和 returnAddress 类型 (§2.3.3)。

数值类型由整数类型 (§2.3.1) 和浮点类型 (§2.3.2) 组成。

整数类型有:

  • byte,其值为8位有符号二进制补码整数,默认值为0

  • short,其值为 16 位带符号二进制补码整数,默认值为 0

  • int,其值为 32 位有符号二进制补码整数,默认值为 0

  • long,其值为64位有符号二进制补码整数,默认值为0

  • char,其值为 16 位无符号整数,表示基本多语言平面中的 Unicode 码位,采用 UTF-16 编码,默认值为空码位 ('\u0000')

现在,对于boolean,情况略有不同。来自§2.3.4

虽然 Java 虚拟机定义了一个boolean 类型,但它只提供了非常有限的支持。没有 Java 虚拟机指令专门用于对 boolean 值的操作。相反,Java 编程语言中对布尔值进行操作的表达式被编译为使用 Java 虚拟机 int 数据类型的值。

根据您使用的是byte[] 还是int[],您可以看到字节码的差异,因此它们并不相同:

byte[] b = {42};
ICONST_1 纽瓦雷 T_BYTE DUP ICONST_0 比普什 42 巴斯托 阿斯托尔 1

int[] b = {42};
ICONST_1 纽瓦雷 T_INT DUP ICONST_0 比普什 42 商城 阿斯托尔 1

真的是节省空间吗?

是的,很可能是这样,尤其是当数组非常大时。

按位运算在 Ints 上是否按预期工作?

是的,他们有。

【讨论】:

  • 规范的链接很棒。它有没有提到a cast is needed for a = (byte)(b+c);
  • @SpellingD 这将包含在语言规范中,而不是 JVM 规范中。但似乎 OP 已经知道这一点。
【解决方案2】:

byte + byte = int 确实需要强制转换,但bytes 是用内存中的 8 位数据实现的,而ints 是 32 位。因此,使用bytes 会使数组占用的内存量减少4倍。

例如,如果您有一个由 bytes 组成的 10 x 10 数组,其大小将为 800,但由 ints 组成的 10 x 10 数组的大小将为 3200。

More information on this

【讨论】:

    【解决方案3】:

    答案取决于您是使用byte 类型的单个变量还是使用字节数组byte[]。字节数组确实节省了空间,每个 Java 字节只使用一个字节的内存(加上数组对象的恒定数量的内务数据)。但是,byte 类型的单个局部变量实际上作为int 存储在堆栈上,并占用相应的 4 字节内存。这甚至在字节码中表示 - 有操作码 baload - “从数组加载字节或布尔值”,但没有用于从局部变量加载字节的操作码,例如用于整数的 iload。同样,本地的charboolean 变量实际上以int 形式存储在堆栈中,并使用基于int 的操作码来访问它们。

    条目2.6.1 in JLS 还说所有局部变量在堆栈上占用一个或两个“槽”,因此单槽类型 byte、char、float 和 int 都占用相同的空间。 JVM 无法寻址小于一个这样的槽的单元,所以在一个字节的情况下,可以说浪费了 3 个字节。

    总结一下:使用byte 数组 以节省空间,但对于单个变量,使用byte 而不是int不会节省空间,甚至可能会对性能产生很小的负面影响(但是,如果您需要 byte 的语义,例如计数器包装行为等,则可能需要它。

    【讨论】:

      【解决方案4】:

      是的,当你执行一个字节加法时,返回值总是一个整数,原因是 8bit + 8bit 加法总是会产生一个大于 8bit 的值。

      例如

      十进制 |二进制

      255 |   1111 1111
      121 |   0111 1001
      

      376 | 1 0111 1000
      

      所以如果你再次尝试将它存储在一个字节中,肯定会导致数据丢失。 如果类型转换为字节,您将得到“120”而不是 376。

      您绝对可以使用 int 代替 byte,并且位操作也可以在 int 上完美运行。 参考:http://www.tutorialspoint.com/java/java_bitwise_operators_examples.htm

      【讨论】:

      • 从技术上讲,位移运算符无法正常工作,但其他运算符可以;)
      • 酷...感谢您指定这一点,我个人从未遇到过使用位移运算符。我也会记下它..:) 只是想知道移位运算符有什么问题(以防万一你想分享)
      猜你喜欢
      • 1970-01-01
      • 2012-02-05
      • 2010-10-30
      • 1970-01-01
      • 2010-11-08
      • 2017-03-18
      • 2019-01-29
      • 2019-08-08
      相关资源
      最近更新 更多