0

我需要知道为什么会发生以下情况,在这段代码(最后两个块)中,我希望输出完全相同,但本地对象(它们只是对列表中对象的引用,对吗?)处于旧状态,而列表已更新。我有一个错误,因为我的游戏代码中有一个类似的复制过程(基于图块,对象交换位置,所以我想为什么不只是交换它们的引用......)

例子:

package game;

import java.util.ArrayList;


public class Tester {
private String s;
private Foo foo;

public Tester(String s, String f) {
    this.s = s;
    this.foo = new Foo(f);
}

class Foo {
    private String f;

    public Foo(String f) {
        this.f = f;
    }
}

@Override
public String toString() {
    return foo.f + ":" + s;
}
public void swap(Tester other) {
    String tempS = this.s;
    Foo tempFoo = this.foo;

    this.s = other.s;
    this.foo = other.foo;
    other.s = tempS;
    other.foo = tempFoo;

}



public static void main(String[] args) {
    ArrayList<Tester> test = new ArrayList<Tester>();
    test.add(new Tester("First", "1"));
    test.add(new Tester("Second", "2"));

    System.out.println("After initializing list");
    for (Tester t : test) {
        System.out.println(t);
    }

    Tester first = test.get(0);
    Tester second = test.get(1);
    Tester tmp = first;

    first = second;
    second = tmp;

    System.out.println("\nAfter temps");
    System.out.println(first);
    System.out.println(second);

    System.out.println("\nList changed after temps?");
    for (Tester t : test) {
        System.out.println(t);
    }

    System.out.println("\nAfter swap");
    first.swap(second);
    System.out.println(first);
    System.out.println(second);

    System.out.println("\nList after swap");
    for (Tester t : test) {
        System.out.println(t);
    }
}
}

和输出:

After initializing list
1:First
2:Second

After temps
2:Second
1:First

List changed after temps?
1:First
2:Second

After swap
1:First
2:Second

List after swap
2:Second
1:First

我想我有点不清楚,我总是先打印出第二个(对象),所以“交换后”应该看起来完全像“交换后的列表”,列表在交换本地对象后发生了变化,本地对象(再一次,仅仅引用列表中的那些?)没有。

对于答案中的评论:虽然我的困惑被消除并且我的问题得到了解决,但我在问是否有可能获得列表对对象的实际引用,以便当我将它指向其他东西时,列表也会自动指向那是别的东西。在下面的示例中,Foo a首先指向Foo具有属性的对象A,但该引用来自list.get()。现在,如果我将它指向new Turtles()列表仍将指向Foo with A. 在此处输入图像描述

我希望有一个“硬”引用,这样当我指向海龟时,arraylist 就会指向海龟。 在此处输入图像描述

这将使交换更容易,但我不确定如何实现一个可以做到这一点的列表(如果可能的话),这将非常适合我的游戏的特定需求。

4

2 回答 2

3

使用对象时需要记住的是,保存对象的变量实际上并不代表对象。变量的值是内存中指向对象所在位置的指针。

通过扩展,某种类型的对象的 ArrayList 实际上并不包含对象。它保存对象引用,或指向内存中对象位置的指针。

当你说:

Object a = new Object();
Object b = new Object();
a = b;

您正在设置指向的指针a的值;换句话说,由于两者和都指向内存中的同一个对象,因此更改一个会更改另一个。 bab

Now to answer your question, with this in mind. If you pull two object references out of an ArrayList, and then swap them, you've swapped the references to the objects; however, the references haven't changed location in the ArrayList. This explains the first three outputs.

Once you do an internal swap, however, you've changed the values stored in each object. This means that, though the pointers to the first and second objects are still the same in memory, their internal information has been swapped.

This explains the last two outputs.

(Note, this is also why you have to use System.arraycopy instead of setting int[] a equal to int[] b; if you were to do the latter, then changing a would change b.)

于 2013-04-07T20:16:00.747 回答
1

实际上,您的交换方法不会交换对象本身,而只会交换它们包含的值,字符串s是按值交换的,对象foo是按引用交换的。

当您使用从列表中获取元素时get(index),除了列表所持有的内部引用之外,您实际上还获得了对该对象的引用,因此您有两个指向同一个对象的引用。

要真正交换列表的元素,您应该使用 List 的set方法,如下所示:

Tester tmp = test.get(index);
test.set(index, test.get(index+1));
test.set(index+1, tmp);

通过这种方式,元素在列表中被交换,因此对其进行迭代将打印您期望的结果。您拥有的swap方法将过时。

于 2013-04-07T20:28:19.237 回答