-2

我的问题是关于幕后引用:)

所以我试图编写一个递归实现来查找给定 ArrayList (getPermsOfMe) 的所有排列。我在我要询问的两个特定行上写了“看这里”。我将 thisPerm 添加到 allPermutations 中,然后稍后在代码中更改 thisPerm,然后将 allPermutations 中先前添加的值更改为新值。

public ArrayList<ArrayList<Integer>> allPermsHelper(ArrayList<Integer> getPermsOfMe, ArrayList<ArrayList<Integer>> allPermutations, ArrayList<Integer> thisPerm){
    if (getPermsOfMe.isEmpty()){
        System.out.println("thisPerm = " + thisPerm);
        allPermutations.add(thisPerm); //LOOK HERE
        System.out.println("allPermutations = " +allPermutations);
    }
    else {
        for (int i = 0; i<ofMe.size(); i++){

            //swapping the two specified elements in getPermsOfMe
            x = getPermsOfMe.get(i);
            getPermsOfMe.set(i, getPermsOfMe.get(getPermsOfMe.size()-1));
            getPermsOfMe.set(getPermsOfMe.size()-1, x);

            if (thisPerm.isEmpty()){
                thisPerm.add(getPermsOfMe.remove(getPermsOfMe.size()-1));
            }
            else{
                thisPerm.add(0,getPermsOfMe.remove(getPermsOfMe.size()-1));
            }

            allPermsHelper(getPermsOfMe, allPermutations, thisPerm);  
            getPermsOfMe.add(0,thisPerm.remove(0)); // LOOK HERE
        }
    } 
    return allPermutations;
}

//an example output (if getPermsOfMe was [123]):
thisPerm = [123]
allPermutations = [[123]]
thisPerm = [231]
allPermutations = [[231],[231]]
thisPerm = [321]
allPermutations = [[321],[321],[321]]
... 

myQuestion 是为什么(就对象和引用而言)先前的值在添加后不会保持不变。所以首先我添加了[123]。接下来我添加了 [231],但后来 allPermuations 是 [[231][231]] 而不是 [[123][231]]。

此外,对我来说,一旦添加它,该值就不会成立,这似乎有点违反直觉。Java(以及我假设其他一些语言)这样做是有原因的吗?

这是我第一次在 stackoverflow 上提问,所以如果我应该做些什么来让我的问题更容易或者让我知道的话。

4

2 回答 2

0

好吧,我现在明白了:) 这是一些更好的示例代码:

    ArrayList<Integer> list = new ArrayList<Integer>();
    ArrayList<ArrayList<Integer>> listOfList = new ArrayList<ArrayList<Integer>>();
    list.add(13);
    list.add(42);
    listOfList.add(list);
    System.out.println("list = " + list);
    System.out.println("listOfList = " + listOfList);

    list1.add(46);
    System.out.println("list = " + list);
    System.out.println("listOfList = " + listOfList);

有输出:

list = [13, 42]
listOfList = [[13, 42]]
list = [13, 42, 46]
listOfList = [[13, 42, 46]]

你期望它是:

list = [13, 42]
listOfList = [[13, 42]]
list = [13, 42, 46]
listOfList = [[13, 42]]

问题是,在 Java 中,列表是对象的集合(或者可能是原语,但在这种情况下,我们关注的是列表列表,即对象列表)。对象包含可修改的数据。如果我们有一所高中的学生名单,并且我们改变了学生,难道不应该在将他们直接放入其中的所有列表中都改变他们吗?所以Java就是这样工作的,通过在幕后使用内存指针。如果您想为一所静态的高中制作学生列表,则必须克隆所有学生,然后将它们放入您的列表中。同样在 Java 中,您需要克隆对象以确保它的修改不会影响列表。

于 2012-11-05T01:10:46.227 回答
0

如何:在幕后,任何适合 an 的东西Object都只是一个参考,这包括列表和数组。这与诸如intor之类的原语不同double

int primitive = 14;
int anotherPrimitive = primitive;
System.out.println(anotherPrimitive); // 14
primitive = 12;
System.out.println(anotherPrimitive); // still 14

String[] array = new String[] {"this is a string in the array"};
String[] anotherArray = array;
System.out.println(anotherArray); // ["this is a string in the array"]
array[0] = "now i've changed it";
System.out.println(anotherArray); // ["now i've changed it"]

碰巧 aArrayList是一种对象,它存储对象引用。这意味着,如果您更改它指向的对象,列表中的内容也会发生变化。

为什么:在没有用户明确询问的情况下自动复制整个对象图没有多大意义。存储引用非常便宜(内存中 4 或 8 个字节),复制也非常便宜(通常需要一个处理器周期)。double每次有人键入时复制 1000 秒的数组doubleList.add(aThousandDoubles);可能会不必要地浪费大量时间和内存。此外,也许您不想要不同的参考;也许你有一个,如果每次你将一个项目添加到列表中时,实现都复制对象List<Foo> monitoredFoos,你将失去读取更改的能力。List

因此,让简单的实现简单地存储对现有实例的引用是有意义的add,并留给程序员复制对象当且仅当您想要并且需要复制对象时。

于 2012-11-05T01:13:25.527 回答