【问题标题】:Do arrays in Java store data or pointersJava中的数组是否存储数据或指针
【发布时间】:2018-07-30 16:11:15
【问题描述】:

我正在阅读有关数据局部性的内容,并希望使用它来改进我正在编写的游戏引擎。

假设我在不同时间创建了五个对象,现在它们都位于内存中的不同位置,而不是彼此相邻。如果我将它们全部添加到一个数组中,该数组是否只保存指向这些对象的指针并且它们将保留在内存中的同一位置,或者将它们全部添加到一个数组中重新排列它们并使它们连续。

我问这个是因为我认为使用数组是使它们连续的好方法,但我不知道数组是否能解决我的问题!

【问题讨论】:

  • 一个数组T[] 只保存对象引用。
  • 这有 99.99% 的可能性是过早的优化。努力让你的代码可读和扎实,知道你的数据结构的时间复杂度,小心 IO。仅当您遇到性能问题时才进行优化,并且您已经证明局部性是问题所在。对于 5 个对象,它不会。
  • @JBNizet 我没有说我那里只有 5 个对象,这只是一个例子来说明我的意思,但感谢您的回答。
  • 你正在创建一个游戏引擎,但不知道 JVM 是如何管理内存的?
  • @BheshGurung 只是因为我不知道东西是如何存储的,并不意味着我不太了解 java -_- 一个有用的答案,谢谢。

标签: java arrays data-structures


【解决方案1】:

tl;博士

操作对象的引用数组对对象没有影响,并且对对象在内存中的位置没有影响

对象

对象的array 实际上是对象的引用(指针)数组。 pointer 是内存中另一个位置的地址。

我们将数组称为保存对象,但这在技术上并不准确。因为 Java 本身并不向我们作为程序员公开指针,所以我们通常不知道它们的存在。当我们访问数组中的一个元素时,我们实际上是在检索一个指针,但 Java 会立即跟随该指针来定位内存中其他位置的对象。

这种自动查找,跟随指向对象的指针,使指针数组感觉就像一个对象数组。 Java 程序员认为她的数组保存着她的对象,而实际上这些对象距离hop-skip-and-a-jump 远。

Java 中的数组被实现为连续的内存块。对于对象数组,指向这些对象的指针存储在连续内存中。但是当我们访问元素时,我们会跳转到内存中的另一个位置来访问我们想要的实际对象。

添加元素可能是“便宜的”,因为如果内存恰好在内存中的隔壁可用,则可以将其分配给数组以为更多元素腾出空间。在实践中,这不太可能。很有可能一个新数组必须在内存的其他地方构建,所有指针都被复制到新数组,然后丢弃原始数组。

这样的新数组和复制是“昂贵的”。在可行的情况下,我们希望避免这种操作。如果您知道数组可能的最大大小,请在声明数组时指定该大小。整个连续内存块被立即声明,数组中的内容为空,直到您稍后为元素分配一个指针。

插入数组的中间也很昂贵。要么构建一个新数组并复制元素,要么必须将插入点之后的所有元素向下移动到它们的相邻位置。

对数组的这些操作都不会影响对象。 对象在内存的以太中四处飘荡。对象对数组一无所知。对数组的操作不会影响对象,也不会影响它们在内存中的位置。唯一的关系是,如果数组中保存的引用是最后一个仍然指向该对象的引用,那么当该数组元素被清除或删除时,该对象将成为garbage-collection 的候选对象。

原语

在 Java 中,八种 primitive 类型(byteshortintlongfloatdoublebooleanchar)不是对象/类而不是Object-Oriented Programming。与对象相比,它们的一个优点是速度快且占用内存少。

基元数组将值保存在数组本身中。因此,这些值彼此相邻存储,在内存中是连续的。没有参考/指针。不要在内存中乱跳。

至于添加或插入,上述行为同样适用。除了不是指针被打乱,实际的原始值被打乱。

提示

在商业应用中,通常最好使用对象。

这意味着使用包装类而不是原语。例如,Integer 而不是 int。 Java 中的auto-boxing 工具通过在原始值和它们的对象包装器之间自动转换,使这变得更容易。

首选对象意味着使用Collection 而不是数组,通常是List,特别是ArrayList。或者对于不可变的使用,从新的 List.of 方法返回一个 List 实现。

与商业应用相比,在速度和内存使用率至关重要的极端情况下(例如您的游戏引擎),则应充分利用数组和原语。

将来,如果Project Valhalla 中所做的工作取得成果,对象和原语之间的区别可能会变得模糊。

【讨论】:

  • 美丽的解释。
【解决方案2】:

数据或值存储在对象中,并使用对象的引用检索值。让我清楚一点,Java 中的数组是以对象的形式存储的。因此毫无疑问,对象存储值并使用该特定对象的引用变量进行访问。希望你明白了。

【讨论】:

  • 如果我知道了,这意味着数组的所有元素实际上在内存中都是连续的?我得到另一个答案,告诉我它们不会是连续的……我很困惑。
  • @Joza100 如果是引用类型的数组,IOW Object,数组存储指针。指针将是连续的。实际对象将在任何地方。
【解决方案3】:

Java 只处理对对象的引用。因此,不能保证数组的元素在内存中是连续的。

编辑:猜猜这个答案不是那么清楚。我的错。我的意思是不能保证对象本身是连续的,尽管引用是连续的,因为一维数组是连续存储的。尽管如此,Basil Bourque 的回答完美地解释了这是如何工作的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    • 2014-11-23
    • 2015-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多