为什么是API而不是java_关于优化:为什么Java API使用int而不是short或byte?

为什么short甚至byte就足够了,为什么Java API使用int?

示例:类Calendar中的DAY_OF_WEEK字段使用int。

如果差异太小,那么为什么这些数据类型(short,int)完全存在?

已经指出了一些原因。例如," ...(几乎)对byte,short的所有操作将把这些原语提升为int"这一事实。但是,下一个明显的问题是:为什么将这些类型提升为int?

因此,要更深入一点:答案可能只是与Java虚拟机指令集有关。如Java虚拟机规范的表中所概述,所有整数算术运算(如加,除等)仅适用于类型int和类型long,而不适用于较小的类型。

(顺便说一句:较小的类型(byte和short)基本上仅用于数组。像new byte[1000]这样的数组将占用1000个字节,而像new int[1000]这样的数组将占用4000个字节) /子>

现在,当然可以说:" ...下一个明显的问题是:为什么这些指令仅提供给int(和long)?"。

上面提到的JVM Spec中提到了一个原因:

If each typed instruction supported all of the Java Virtual Machine's run-time data types, there would be more instructions than could be represented in a byte

另外,可以将Java虚拟机视为真实处理器的抽象。为较小的型号引入专用的算术逻辑单元将是不值得的:它需要额外的晶体管,但仍然只能在一个时钟周期内执行一次加法运算。设计JVM时,主要的体系结构是32位,恰好适合32位int。 (涉及到64位long值的操作是作为特殊情况实现的)。

(注意:考虑到可能的向量化等,最后一段有点过分简化,但是应该给出基本思想,而不必深入探讨处理器设计主题) sub>

编辑:简短的附录,重点放在问题的示例上,但从更一般的意义上讲:还可以问一下使用较小类型存储字段是否没有好处。例如,人们可能认为可以通过将Calendar.DAY_OF_WEEK存储为byte来节省内存。但是在这里,Java类文件格式开始起作用:类文件中的所有字段至少占据一个"槽",其大小为一个int(32位)。 ("宽"字段double和long占据两个插槽)。因此,将字段显式声明为short或byte也不会节省任何内存。

我猜想为什么将操作数提升为int的逻辑也与C和C ++中使用的基本原理有关

@ Marco13"因此明确地将字段声明为short或byte也不会节省任何内存。" 真的吗? 我不认为那是正确的。

@ACV严格来说,实现可以选择存储更紧凑的形式,但是"虚拟地"(即由虚拟机)公开的格式会将值视为至少具有int的大小。 如果您引用了另一个实现,请ID更新答案并相应地插入链接。

(几乎)byte,short上的所有操作会将其提升为int,例如,您不能编写:

short x = 1;

short y = 2;

short z = x + y; //error

使用int时,算术更加简单明了,无需强制转换。

就空间而言,差异不大。 byte和short会使事情复杂化,因为我们谈论的是固定数量的变量,所以我认为这种微优化不值得。

当您为嵌入式设备编程或处理文件/网络时,byte是相关且有用的。这些原语也受到限制,如果将来计算可能超出其限制怎么办?尝试考虑Calendar类的扩展,该扩展可能会演化出更大的数字。

还要注意,在64位处理器中,本地变量将保存在寄存器中,并且不会使用任何资源,因此使用int,short和其他原语根本不会有任何区别。此外,许多Java实现将变量*(和对象)对齐。

* byte和short如果是局部变量,类变量甚至实例变量,则它们与int占据相同的空间。为什么?因为在(大多数)计算机系统中,变量地址是对齐的,所以例如,如果您使用单个字节,则实际上将以两个字节结尾-一个用于变量本身,另一个用于填充。

另一方面,在数组中,byte占用1个字节,short占用2个字节,而int占用4个字节,因为在数组中,仅其开头和结尾必须对齐。如果您要使用System.arraycopy(),这会有所不同,那么您会真正注意到性能上的差异。

有趣的事实:如果对两个值都使用final修饰符,则它将起作用。:)

因为与短裤相比,使用整数时算术运算更容易。假设常量确实是由short值建模的。然后,您将必须以这种方式使用API??:

short month = Calendar.JUNE;

month = month + (short) 1; // is july

注意显式转换。在算术运算中使用短值时,它们会隐式提升为int值。 (在操作数堆栈上,甚至将short表示为int。)使用起来非常麻烦,这就是为什么int值通常是常量首选的原因。

与此相比,由于仅存在固定数量的这样的常数,所以存储效率的增益是最小的。我们正在谈论40个常数。将其存储从int更改为short可以使40 * 16 bit = 80 byte安全。请参阅此答案以获取更多参考。

如果您使用将整数常量存储在它们适合的最小类型中的哲学,那么Java将会遇到一个严重的问题:每当程序员使用整数常量编写代码时,他们都必须特别注意自己的代码,以检查代码的类型。常量很重要,如果需要,可以在文档中查找类型和/或执行任何需要的类型转换。

因此,既然我们已经概述了一个严重的问题,那么您希望通过这种理念获得什么好处?如果该更改的唯一可观察到的运行时效果是通过反射查找常量时得到的类型,那我就不会感到惊讶。 (当然,由于懒惰/无意识的程序员引入的任何错误都没有正确考虑常量的类型)

权衡利弊非常容易:这是一个糟糕的哲学。

虚拟机的设计复杂度取决于它可以执行多少种操作。此外,具有"乘法"之类的四种指令实现要容易得多,每个实现分别用于32位整数,64位整数,32位浮点和64位浮点。除上述以外,较小数字类型的版本也是如此。一个更有趣的设计问题是为什么应该有四种类型,而不是更少(使用64位整数执行所有整数计算和/或使用64位浮点值执行所有浮点计算)。使用32位整数的原因是,Java有望在许多平台上运行,在这些平台上,对32位类型的作用速度可以与对16位或8位类型的作用速度一样快,但是对64位类型的操作将很明显慢点。即使在使用16位类型的平台可以更快地工作的平台上,使用32位数量的额外费用也将被仅具有32位类型的简单性所抵消。

至于对32位值执行浮点计算,其优势还不太清楚。在某些平台上,可以通过将所有操作数转换为高精度类型,相加然后将结果转换回32位浮点数进行存储来最快速地执行类似float a=b+c+d;的计算。在其他平台上,使用32位浮点值执行所有计算会更高效。 Java的创建者认为,应该要求所有平台都以相同的方式执行操作,并且他们应该支持32位浮点计算比长计算更快的硬件平台,即使这会严重降低PC的速度在典型的PC以及许多没有浮点运算单元的计算机上,浮点运算的精度和精度都很高。请注意,顺便说一句,根据b,c和d的值,在计算类似于上述float a=b+c+d;的表达式时使用高精度中间计算有时会产生比所有中间操作数所获得的结果要精确得多的结果。以float精度计算,但有时会产生一个精度略低的值。无论如何,Sun决定一切都应以相同的方式完成,他们选择使用最小精度float值。

注意,较小的数据类型的主要优点在将大量数据存储在一个数组中时显而易见。即使小于64位的类型的单个变量没有优势,也值得拥有可以更紧凑地存储较小值的数组;使局部变量为byte而不是long会节省七个字节;具有1,000,000个数字的数组将每个数字保留为byte,而不是long波动7,000,000字节。由于每种数组类型仅需要支持一些操作(最值得注意的是读取一个项目,存储一个项目,在一个数组中复制一系列项目或将一系列项目从一个数组复制到另一个),因此增加了复杂性数组类型并不像具有更多类型的直接可用离散数值那样复杂。

实际上,这是一个小优势。如果你有

class MyTimeAndDayOfWeek {

byte dayOfWeek;

byte hour;

byte minute;

byte second;

}

然后,在典型的JVM上,它需要与包含单个int的类一样多的空间。内存消耗将舍入为8或16个字节的下一个整数倍(IIRC,这是可配置的),因此真正节省的情况很少见。

如果相应的Calendar方法返回byte,则该类将更易于使用。但是没有这样的Calendar方法,只有get(int)由于其他字段而必须返回int。较小类型的每个操作都会提升为int,因此您需要进行大量转换。

您很可能会放弃并切换到int或编写诸如

void setDayOfWeek(int dayOfWeek) {

this.dayOfWeek = checkedCastToByte(dayOfWeek);

}

那么DAY_OF_WEEK的类型无关紧要。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值