英文:
Clearing subarray without affecting main array
问题
我想将一些随机值添加到一个二维 ArrayList 中,方法是首先创建一个带有随机生成值的一维数组,然后将其添加到主数组中,然后清空这个一维数组,然后重复这个过程几次。
这是我的代码:
ArrayList<ArrayList<Integer>> a = new ArrayList<>();
ArrayList<Integer> b = new ArrayList<>();
for(int i=0; i<5; i++) {
b.add(r.nextInt(10));
b.add(r.nextInt(10));
System.out.println("B - "+b);
a.add(b);
b.clear();
}
System.out.println(a);
这是我的输出:
B - [7, 6]
B - [4, 4]
B - [3, 7]
B - [3, 7]
B - [0, 1]
A - [[], [], [], [], []]
[]
请问有人可以修复这个问题并解释一下为什么会出现这种情况吗?
英文:
I wanted to add some random values to a two-dimensional ArrayList by creating a one dimensional array with some randomly generated values, adding it to the main array then clearing the one dimensional array and repeating this proccess a few times.
Here's what I wrote:
ArrayList<ArrayList<Integer>> a = new ArrayList<>();
ArrayList<Integer> b = new ArrayList<>();
for(int i=0;i<5;i++) {
b.add(r.nextInt(10));
b.add(r.nextInt(10));
System.out.println("B - "+b);
a.add(b);
b.clear();
}
System.out.println(a);
This is my output:
B - [4, 4]
B - [3, 7]
B - [3, 7]
B - [0, 1]
A - [[], [], [], [], []]
[]
Could someone please fix this and explain why this occurs?
答案1
得分: 1
你应该尝试重新初始化数组b,而不是清除它。
英文:
You should try re-initializing the array b instead of clearing it.
答案2
得分: 1
当你写下:
ArrayList<Integer> b = new ArrayList<>();
这就是在说:创建一个类型为ArrayList的对象(宝藏箱子),并将其放在堆上(埋在沙子里),因为所有对象都是在那里创建的(所有对象都被埋在沙子里,这就是Java的工作方式)。这个对象现在和将来都没有名字(对象(宝藏箱子)没有名字)。
然后,创建一个新的引用(可以持有宝藏地图的纸)。将引用的值设置为指向刚刚创建的对象(在地图上标记出刚刚埋在沙子里的宝藏的位置)。我们将这个引用(宝藏地图)称为 b
(在Java中,变量有名字,非基本类型的变量是宝藏地图。通过这种方式,虽然宝藏没有名字,但地图可以有)。
然后,你执行:
b.add(r.nextInt(10));
b
和 add
之间的 .
是Java的写法,表示:“取出引用 b
,跟随它,并在你找到的对象上调用 add
方法”(取出我们称为 b
的宝藏地图,跟随它,挖掘。打开箱子,在找到的东西上运行添加操作)。你应该理解 .
在Java中是指 跟随地图并挖掘。
然后你执行:
a.add(b);
这是关键部分:a
是 宝藏地图的列表。你似乎误以为 a
是宝藏的列表。在Java中这是不可能的,所有非基本类型都是引用,也就是说,所有非基本类型都是通过宝藏地图来操作的,而不是宝藏。
所以,用宝藏来解释,这个算法做了以下操作:
- 创建一个新的宝藏箱子,上面写着:“这个箱子装有宝藏地图!”。埋在沙子里,画一张宝藏地图,称之为
a
。 - 再创建一个新的宝藏箱子。上面写着:“这个箱子装有随机数字!”。埋起来,画一张地图,叫做
b
。 - 取出你的
b
地图,跟随它,打开箱子,掷骰子,把骰子放进箱子里。 - 重复步骤 #3。
- 复制一份
b
宝藏地图。跟随a
地图,找到装有地图的宝藏箱子,把b
的复制放进去。 - 取出你的
b
地图,跟随它,打开箱子,找到骰子,扔掉它们。 - 重复几次。
所以,最终你只有两个宝藏箱子:一个箱子里有5张完全相同的地图,每张地图都指向另一个你创建的箱子,然后另一个箱子里装满了骰子,然后你又把它们扔了出来,最后箱子是空的。
然后你将所有这些打印出来,这自然证实了上述所有内容:一个包含5个空列表的列表。
实际上,你想要的是每次都创建一个新的宝藏箱子,而不是清空旧的。所以,将:
b.clear();
替换为:
b = new ArrayList<Integer>();
也就是说,代替:“跟随这张宝藏地图,找到箱子,打开箱子,清空所有骰子”,你选择:“创建一个全新的宝藏箱子,埋在沙子里,取出我称为 b
的宝藏地图,清空它,画地图指向我刚刚埋的全新的箱子。保留旧的箱子,里面有骰子,不要碰它”。
英文:
When you write:
ArrayList<Integer> b = new ArrayList<>();
That's saying: Make an object (treasure chest) of type ArrayList and make it on the heap (bury it in the sand), because all objects are made there (all objects are buried in the sand, that's just how java works). This object does not now or ever have names (objects (treasure chests) do not have names).
Then, make a new reference (paper that can hold a treasure map). Set the value of the reference to point at the newly created object (draw a map to location you just buried the freshly created treasure in the sand). We shall call this reference (treasure map) b
(in java, variables have names, and variables of non-primitive types are treasure maps. In that way, whilst treasure cant have a name, maps can).
Then, you do:
b.add(r.nextInt(10));
The .
between b
and add
is java-ese for: "Take the reference 'b', follow it, and invoke the 'add' object on the object you found there" (Take the treasure map we called b
, follow it, and dig. Open the box, run the add job on what you found). You should get into your head that .
is java for follow the map and dig.
Then you run:
a.add(b);
and this is the crucial part: a
is a list of treasure maps. You seem to be under the impression that a is a list of treasures. That's not possible in java, all non-primitives are references, that is, all non-primitive things are done in terms of treasure maps, never treasures.
So, in terms of treasure, this is what this algorithm does:
- Create a new treasure chest, write on it: "This chest holds treasure maps!". Bury it in the sand, draw a treasure map, call the map
a
. - Create another new treasure chest. Write on it: "This chest holds random numbers!". Bury it, draw a map, call it
b
. - Take your
b
map, follow it, open the box, roll a die, put the die in the box. - Repeat #3.
- Take your
b
treasure map and make it a copy of it. Follow thea
map to find the treasure-map-holding treasure chest, and put the copy of the b map in it. - Take your
b
map, follow it, open the box, find the dice, toss em out. - repeat a few times.
So, you end up with only 2 treasure chests, total: One with 5 copies of the exact same map, all a map to find the other chest you made, and then one other chest that you put a bunch of dice into and then tossed em back out again, ending in a state where it is empty.
You then print this all, which naturally confirms all of the above: A list with 5 empty lists.
What you actually want is to create a new treasure chest every time, and not clear the old one. So, take:
b.clear();
and replace that with:
b = new ArrayList<Integer>();
i.e, instead of: "Follow this treasure map, find the chest, open it, remove all the dice", you go with: "Make an entirely new treasure chest, bury it in the sand, take my treasure map called b
, erase it, and draw the map to newly created chest I just buried. Leave the old chest in piece, with the dice in, don't touch that".
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论