为什么不能在Java中将字节数组存储在整数数组中 - java

该代码有效

int h;
byte r;
h=r;

但是这些不是

int[] h;
byte[] r;
h=r;

或说

int[] h =new byte[4];

我想知道为什么?

参考方案

差异首先是由于原始类型和引用类型在行为上的差异。

如果您不熟悉它,原始类型具有“值语义”。这意味着当a = b;a是原始类型(bbyteshortintlongfloatdoubleboolean)执行char时,将复制数字/布尔值。例如:

int a = 3;
int b = a; // int value of a is copied to b
a = 5;
System.out.println(b); // outputs: 3

但是数组是对象,对象具有“引用语义”。这意味着当您执行a = b;(其中ab都声明为数组类型)时,所引用的数组对象将成为共享。从某种意义上说,该值仍会被复制,但是这里的“值”只是指向内存中其他位置的对象的指针。例如:

int[] a = new int[] { 3 };
int[] b = a; // pointer value of a is copied to b, so a and b now point at the same array object
a[0] = 5;
System.out.println(b[0]); // outputs: 5
a = null; // note: 'a' now points at no array, although this has no effect on b
System.out.println(b[0]); // outputs: 5

因此,可以执行int = byte,因为数值将被复制(因为它们都是原始类型),并且因为字节类型的任何可能值都可以安全地存储在int中(它是"widening" primitive conversion)。

但是int[]byte[]都是对象类型,因此当您执行int[] = byte[]时,您要求对象(数组)是共享的(未复制)。

现在您不得不问,为什么一个int数组和一个字节数组不能共享它们的数组内存?如果他们这样做,那意味着什么呢?

整数是字节大小的4倍,因此,如果整数和字节数组具有相同数量的元素,那么这将导致各种废话。如果您尝试以内存有效的方式实现它,那么在访问int数组的元素以查看它们实际上是否为字节数组时,将需要复杂(且非常缓慢)的运行时逻辑。从字节数组内存读取的int数据将必须读取并加宽字节值,而int存储的数据将不得不丢失高3个字节,或者抛出异常,指出空间不足。或者,您可以通过填充所有字节数组以快速但浪费内存的方式来做到这一点,以便每个元素浪费3个字节,以防万一有人要使用字节数组作为int数组。

另一方面,也许您想为每个int压缩4个字节(在这种情况下,共享数组将不具有相同数量的元素,具体取决于用于访问它的变量的类型)。不幸的是,这也造成了废话。最大的问题是它不能跨CPU架构移植。在little-endian PC上,b[0]指的是i[0]的低字节,但在ARM设备上,b[0]可能指向i[0]的高字节(并且在程序运行时可能会更改,因为ARM具有可切换的字节序)。访问数组的length属性的开销也将变得更加复杂,如果字节数组的长度不能被4整除,那该怎么办?

您可以在C中执行此操作,但这是因为C数组没有明确定义的length属性,并且因为C并未尝试保护您免受其他问题的影响。 C不在乎您是否超出数组范围或混淆字节序。但是Java确实在乎,因此在Java中共享阵列内存是不可行的。 (Java没有unions。)

这就是int[].classbyte[].class都分别扩展类Object的原因,而这两个类都不扩展另一个。您不能在声明为指向int数组的变量中存储对字节数组的引用,就像您不能在List类型的变量中存储对String的引用一样;它们只是不兼容的类。

JAVA:字节码和二进制有什么区别? - java

java字节代码(已编译的语言,也称为目标代码)与机器代码(当前计算机的本机代码)之间有什么区别?我读过一些书,他们将字节码称为二进制指令,但我不知道为什么。 参考方案 字节码是独立于平台的,在Windows中运行的编译器编译的字节码仍将在linux / unix / mac中运行。机器代码是特定于平台的,如果在Windows x86中编译,则它将仅在Win…

Java-将int更改为ascii - java

java有没有办法将int转换为ascii符号? 参考方案 您是否要将int转换为char?:int yourInt = 33; char ch = (char) yourInt; System.out.println(yourInt); System.out.println(ch); // Output: // 33 // ! 还是要将int转换为Stri…

Java:线程池如何将线程映射到可运行对象 - java

试图绕过Java并发问题,并且很难理解线程池,线程以及它们正在执行的可运行“任务”之间的关系。如果我创建一个有10个线程的线程池,那么我是否必须将相同的任务传递给池中的每个线程,或者池化的线程实际上只是与任务无关的“工人无人机”可用于执行任何任务?无论哪种方式,Executor / ExecutorService如何将正确的任务分配给正确的线程? 参考方案 …

java:继承 - java

有哪些替代继承的方法? java大神给出的解决方案 有效的Java:偏重于继承而不是继承。 (这实际上也来自“四人帮”)。他提出的理由是,如果扩展类未明确设计为继承,则继承会引起很多不正常的副作用。例如,对super.someMethod()的任何调用都可以引导您通过未知代码的意外路径。取而代之的是,持有对本来应该扩展的类的引用,然后委托给它。这是与Eric…

Java:BigInteger,如何通过OutputStream编写它 - java

我想将BigInteger写入文件。做这个的最好方式是什么。当然,我想从输入流中读取(使用程序,而不是人工)。我必须使用ObjectOutputStream还是有更好的方法?目的是使用尽可能少的字节。谢谢马丁 参考方案 Java序列化(ObjectOutputStream / ObjectInputStream)是将对象序列化为八位字节序列的一种通用方法。但…