【发布时间】:2010-12-05 02:49:12
【问题描述】:
除了在流式传输中使用 (byte[]) 之外,我并没有真正看到 byte 和 short 使用得太多。另一方面,我看到长期使用实际值为|100|的情况。和字节会更合适。这是由于现在内存相对便宜的性质,还是只是开发人员不必担心的细节?
【问题讨论】:
标签: java
除了在流式传输中使用 (byte[]) 之外,我并没有真正看到 byte 和 short 使用得太多。另一方面,我看到长期使用实际值为|100|的情况。和字节会更合适。这是由于现在内存相对便宜的性质,还是只是开发人员不必担心的细节?
【问题讨论】:
标签: java
在为内存或磁盘空间不足的嵌入式设备编程时使用它们。例如电器和其他电子设备。
字节还用于低级 Web 编程,您可以使用标头等向 Web 服务器发送请求。
【讨论】:
byte 数据类型在处理来自文件或网络连接的原始数据时经常使用,尽管它主要用作byte[]。 short 和 short[] 类型通常与 GUI 和图像处理(用于像素位置和图像大小)以及声音处理结合使用。
使用byte 或short 的主要原因之一是为了清晰。程序代码不明确地声明只使用 8 位或 16 位,并且当您不小心使用更大的类型(没有适当的类型转换)时,您会收到编译错误。 (诚然,在编写代码时这也可能被视为令人讨厌的事情......但是类型转换的存在再次标志着读者发生截断的事实。)
在简单变量中使用byte 或short 而不是int 不会节省任何空间,因为大多数Java 实现都会在字边界上对齐堆栈变量和对象成员。但是,原始数组类型的处理方式不同;即boolean、byte、char 和short 数组的元素是字节对齐的。但除非数组的大小或数量很大,否则它们不会对应用程序的整体内存使用量产生任何重大影响。
所以我猜开发人员没有像您(C 开发人员?)所期望的那样使用 byte 或 short 的主要原因是它确实没有太大(或通常任何)差异. Java 开发人员不会像老式 C 开发人员那样痴迷内存使用 :-)。
【讨论】:
在 64 位处理器中,寄存器都是 64 位的,因此如果将局部变量分配给寄存器并且是布尔值、字节、短、字符、整数、浮点、双精度或长整数,则不会使用内存,不节省任何资源。 对象是 8 字节对齐的,因此它们总是占用内存中 8 字节的倍数。这意味着 Boolean、Byte、Short、Character、Integer、Long、Float 和 Double、AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference 都使用相同的内存量。
如前所述,短类型用于数组和读/写数据格式。即便如此,恕我直言,short 也不会经常使用。
还值得注意的是,一个 GB 的服务器成本约为 80 英镑,因此一个 MB 约为 8 便士,一个 KB 约为 0.008 便士。 byte 和 long 之间的差异约为 0.00006 便士。你的时间比这更有价值。尤其是如果您遇到过由于数据类型太小而导致的错误。
【讨论】:
在处理二进制格式和DataInput/DataOutput 实例时,我最常使用short 和byte 类型。如果规范说下一个值是 8 位或 16 位值,并且将它们提升为 int 没有任何价值(也许它们是位标志),那么它们是显而易见的选择。
【讨论】:
bytes 和 shorts 的算术比ints 更尴尬。例如,如果b1 和b2 是两个byte 变量,则不能写byte b3 = b1 + b2 来添加它们。这是因为 Java 从不在内部对小于 int 的任何事物进行算术运算,因此表达式 b1 + b2 的类型为 int,即使它只是添加两个 byte 值。你必须改写byte b3 = (byte) (b1 + b2)。
【讨论】:
Stephen C's answer above 不正确。 (对不起,我没有足够的声望点来评论,所以我必须在这里发布答案)
他说
“在简单变量中使用 byte 或 short 来代替 int 并不能节省任何空间,因为大多数 Java 实现都会在字边界上对齐堆栈变量和对象成员”
这不是真的。以下是在 Oracle JDK1.8.0 上运行的,jol
public class CompareShorts {
public static void main(String[] args) {
System.out.println(VM.current().details());
System.out.println(ClassLayout.parseInstance(new PersonalDetailA()).toPrintable());
System.out.println(ClassLayout.parseInstance(new PersonalDetailB()).toPrintable());
}
}
class PersonalDetailA {
short height;
byte color;
byte gender;
}
class PersonalDetailB{
int height;
int color;
int gender;
}
输出:
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# Objects are 8 bytes aligned.
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
com.hunterstudy.springstudy.PersonalDetailA object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 82 22 01 f8 (10000010 00100010 00000001 11111000) (-134143358)
12 2 short PersonalDetailA.height 0
14 1 byte PersonalDetailA.color 0
15 1 byte PersonalDetailA.gender 0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
com.hunterstudy.springstudy.PersonalDetailB object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e1 24 01 f8 (11100001 00100100 00000001 11111000) (-134142751)
12 4 int PersonalDetailB.height 0
16 4 int PersonalDetailB.color 0
20 4 int PersonalDetailB.gender 0
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
如您所见,使用shorts 和bytes 的类实例占用16 个字节,使用ints 的类实例占用24 个字节。 所以它确实为每个类实例节省了 8 个字节的内存。
【讨论】:
在创建基于 16 位架构的模拟器时,我广泛使用了short。我考虑过使用char,这样我就可以得到无符号的东西,但使用真正整数类型的精神最终胜出。
编辑: 关于当我需要最重要的位时我做了什么的不可避免的问题:我正在模仿的东西碰巧几乎从未被使用过。在少数使用它的地方,我只是使用了按位修饰符或数学黑客。
【讨论】:
我认为在大多数应用程序中,short 没有域含义,因此使用 Integer 更有意义。
【讨论】:
short 等常用于存储图像数据。请注意,真正重要的是位数,而不是算术属性(只会导致提升到int 或更好。
short 还用作 JavaCard 中的数组索引(1.0 和 2.0,IIRC,但不是 3.0,它还具有 HTTP 堆栈和 Web 服务)。
【讨论】:
byte[] 一直在发生;缓冲区,专门用于网络、文件、图形、序列化等。
【讨论】:
大多数时候,开发人员(Java、C#、BASIC 等)没有真正好的技术理由来决定使用 int、short 或 byte - 当然,当容量足够时。如果价值低于 20 亿,那么 int 会是。
您确定我们会有 255 岁以上的人吗?好吧,你永远不知道!
32,767 个可能的国家还不够吗?不要想得太小!
在您的示例中,您可以对包含 100 的字节变量非常满意,如果您绝对确定它永远不会溢出。为什么男生用的最多的是 int?因为……因为。
这是我们大多数人都会做的事情之一,因为我们大部分时间都是这样看的,而且从来没有提出不同的要求。
当然,我并不反对“万物互联”。我只是更喜欢为每种值使用正确的类型,没有压力。
【讨论】:
您遇到的一般信息是byte,通常byte [] 用于处理二进制数据,例如图像文件,或通过网络发送数据。我现在会提到其他用例:
在Java中,String对象使用UTF-16,后者是不可变的,即不能修改。
为了对字符串进行编码,我们将它们转换为与 ASCII 兼容的 UTF-8。一种方法是使用 java core,你可以找到更多的方法去here。
为了执行编码,我们将原始字符串字节复制到一个字节数组中,然后创建所需的字节。下面,我将举一个简单的例子来说明为什么我们需要对字符串进行编码,以及如何做到这一点:
假设您有这个德语单词“Tschüss”并且您使用的是 US-ASCII:
String germanString = "Tschüss";
byte[] germanBytes = germanString.getBytes();
String asciiEncodedString = new String(germanBytes,StandardCharsets.US_ASCII);
assertNotEquals(asciiEncodedString, germanString);
输出将是:
Tsch?ss
因为 US_ASCII 不能识别“ü”。
下面是一个有效的例子:
String germanString = "Tschüss";
byte[] germanBytes = germanString.getBytes(StandardCharsets.UTF_8);
String utf8EncodedString = new String(germanBytes, StandardCharsets.UTF_8);
assertEquals(germanString, utf8EncodedString);
为了说明,Java String 是一个底层使用 char 数组的 Object,包括其他数据,您可以在 this answer 中找到更多信息。
现在想象一下您想要解析大量字符串数据并使用例如split 方法的情况。在这种情况下,您将有不同的对象(不同的 char 数组)分布在内存中的不同位置,这会导致 CPU 的 locality 变差,这与情况相反从一开始就在一个位置有一个字节数组。您可以在这篇有趣的帖子this one 中找到更多信息。
【讨论】: