Why does this method of copying and modifying an array result differently for a one dimensional vs two dimensional array?

huangapple go评论71阅读模式
英文:

Why does this method of copying and modifying an array result differently for a one dimensional vs two dimensional array?

问题

以下是翻译好的部分:

运行以下代码的结果是:

场景 1:
数组 c:[[2, 2, 3], [4, 5, 6]]
数组 d:[[2, 2, 3], [4, 5, 6]]
场景 2:
数组 e:[1 2 3]
数组 f:[2 2 3]

我不明白为什么您可以修改一维数组,然后之后不会影响另一个数组,但对于二维数组却不能做相同的操作。

import java.util.Arrays;

public class Tester {
    public static void main(String args[]) {

        // 场景 1:
        int[][] c = {{1, 2, 3}, {4, 5, 6}};
        int[][] d = new int[c.length][c.length];
        for (int i = 0; i < d.length; i++) {
            d[i] = c[i];
        }

        // 测试副作用
        d[0][0]++;
        // c[0] = d[];

        System.out.println("场景 1:");
        System.out.println("数组 c:" + Arrays.deepToString(c));
        System.out.println("数组 d:" + Arrays.deepToString(d));

        // 场景 2:
        int[] e = {1, 2, 3};       
        int[] f = new int[e.length];
        for (int i = 0; i < f.length; i++) {
            f[i] = e[i];
        }

        // 测试副作用
        f[0]++;

        System.out.println("场景 2:");
        System.out.print("数组 e:");
        printArray(e);
        System.out.print("数组 f:");
        printArray(f);

    }

    public static void printArray(int[] a) {
        System.out.print("[ ");
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i] + " ");
        }
        System.out.println("]");
    }
}
英文:

The result of running the code below is:

Scenario 1: 
Array c: [[2, 2, 3], [4, 5, 6]]
Array d: [[2, 2, 3], [4, 5, 6]]
Scenario 2: 
Array e: [ 1 2 3 ]
Array f: [ 2 2 3 ]

I don't understand why you can modify the one dimensional array afterwards without it affecting the other but you cannot do the same for the two dimensional arrays.

import java.util.Arrays;
public class Tester {
public static void main(String args[]) {
//Scenario 1:
int[][] c = {{1, 2, 3}, {4, 5, 6}};
int[][] d = new int[c.length][c.length];
for (int i = 0; i &lt; d.length; i++) {
d[i] = c[i];
}
//test side effect
d[0][0]++;
//c[0] = d[];
System.out.println(&quot;Scenario 1: &quot;);
System.out.println(&quot;Array c: &quot; + Arrays.deepToString(c));
System.out.println(&quot;Array d: &quot; + Arrays.deepToString(d));
//Scenario 2:
int[] e = {1, 2, 3};       int[] f = new int[e.length];
for (int i = 0; i &lt; f.length; i++) {
f[i] = e[i];
}
//test side effect
f[0]++;
System.out.println(&quot;Scenario 2: &quot;);
System.out.print(&quot;Array e: &quot;);
printArray(e);
System.out.print(&quot;Array f: &quot;);
printArray(f);
}
public static void printArray(int[] a) {
System.out.print(&quot;[ &quot;);
for (int i = 0; i &lt; a.length; i++) {
System.out.print(a[i] + &quot; &quot;);
}
System.out.println(&quot;]&quot;);
}
}

答案1

得分: 1

2D数组?Java里面是没有的。

Java有的是数组的数组。这不是同一回事。

此外,数组是对象。这意味着任何解析为数组的表达式都是一个__引用__。一个指针。就像一张通往宝藏的藏宝图,而不是宝藏本身。所以:

int[] x = new int[]{5, 6, 7};

我拿了一个宝箱,打开它,把一个5分、6分和7分的硬币扔进去。我关闭它,把它埋在沙子里。然后,我拿了一张纸,画了一张通往宝藏的地图。我要把这张地图标记为 x,然后把它放在口袋里。

int[][] y = {{1, 2, 3}, {4, 5, 6}};
// 注意:
// 上面的写法实际上等同于:
int[][] y = new int[][] { new int[] {1, 2, 3}, new int[] {4, 5, 6}};

我拿了两个宝箱。我把1分、2分和3分的硬币放在一个宝箱里,把4分、5分和6分的硬币放在另一个宝箱里。我把它们都埋了,然后为它们制作了藏宝图。

然后我拿了第三个宝箱,打开它,把这些藏宝图放进去(而不是其他的宝箱!!),然后埋起来。然后我又制作了另一张指向这个宝箱的地图,将其标记为 y,并把它也放在口袋里。

y[0] = x;

我把口袋里的 y 地图拿出来,按照地图走,拿出铲子,开始挖掘。我打开宝箱,发现里面是一个装满藏宝图的宝箱。我拿出第一张地图,拿起橡皮擦,把它擦掉。然后我从口袋里拿出 x 地图,复制地图内容过来。我把 y[0] 地图放回宝箱,重新埋起来。我把 yx 地图重新放回口袋(现在如果你按照 y 地图走,找到的第一个宝箱里的地图是我的 x 地图的复制!),然后回家。

x[0] = 100;

我从口袋里拿出 x 地图,按照地图走,开始挖掘,拿出第一个(5分)的硬币扔掉,然后拿出一枚闪亮的100块硬币放回去。

System.out.println(y[0][0]);

我拿出我的 y 地图,按照地图走,挖掘,打开宝箱,拿出第一张地图(记住,它是 x 地图的复制),按照那张地图走,再次挖掘,然后哇!第一个硬币是……一枚价值100块的硬币!哇!得分!

y[0] = new int[] {};

我制作了一个新的宝箱,里面什么都没有,然后把它埋了。然后我拿出我的 y 地图,按照地图走,挖掘,打开宝箱,里面装着更多的藏宝图。我拿出第一张地图,把它擦掉,然后在上面涂鸦,画了一张通往这个新的(空的)宝箱的地图,然后把它埋了。

System.out.println(x[0]);

……这仍然会打印出100。

简而言之:

  • x.yx[] 是Java语言中的说法:按照地图走并挖掘。
  • = 是Java语言中的说法:拿起橡皮擦擦掉,然后拿起笔画一张地图。
  • … 除非是基本类型(intdoublebooleanbyte 等等)- 对于这些类型,就不涉及宝箱了。
英文:

2D arrays? Java does not have them.

What java does have, is arrays of arrays. It's not the same thing.

Also, arrays are objects. Which means any given expression that resolves to an array is a reference. A pointer. It's like a treasure map to treasure, not the treasure itself. So:

int[] x = new {5, 6, 7};

I take a treasure chest, I open it, I toss a 5 cent, 6 cent, and 7 cent coin in it. I close it, bury it in the sand. Then, I take a piece of paper and draw a map to the treasure. I shall label this map x, and I put it in my pocket.

int[][] y = {{1, 2, 3}, {4, 5, 6}};
// NOTE:
// the above is syntax sugar for:
int[][] y = new int[][] { new int[] {1, 2, 3}, new int[] {4, 5, 6}};

I take 2 treasure chests. I put a 1c, 2c, and 3c coin in one, and a 4c, 5c, and 6c coin in the other. I bury both, and make treasure maps for both.

Then I get a third treasure chest, open it, put these maps inside (not the other chests!!), and bury my treasure-chest-full-of-maps. Then I make yet another map to this chest, label it y, and put that in my pocket too.

y[0] = x;

I take my y map out of my pocket, follow it, get out my shovel, and dig. I open the chest and find that it is a treasure-map-containing-chest. I take the first map out, take an eraser, and wipe it out. Then I take the x map out of my pocket and copy the map over. I put the y[0] map back in the treasure chest, bury the treasure chest. I stick my y and x maps back in my pocket (now the first map in the chest you find if you follow the y map is a copy of my x map!), and go home.

x[0] = 100;

I get the x map out of my pocket, follow it, dig down, take the first (5c) coin out and toss it away, then I take a shiny 100 piece-o-eight and put it back.

System.out.println(y[0][0]);

I take my y map, follow it, dig, open the chest, take the first map out (remember, it was a copy of the x map), follow that map, dig again, and lo! The first coin is... a 100 piece-o-eight! Wow! Score!

y[0] = new int[] {};

I make a new treasure chest, put nothing inside, and bury it. I then take my y map, follow it, dig, open the chest, which contains more treasure maps. I take out the first map and erase it, and I scribble down a map to this new (empty) chest I buried.

System.out.println(x[0]);

... that is still going to print 100.

TL;DR:

  • x.y and x[] is java-ese for: Follow the map and dig.
  • = is java-ese for: Take an eraser and wipe, then take a pen and draw a map.
  • ... unless it's primitives (int, double, boolean, byte, etc) - then nevermind all that. No treasure chests involved for those.

huangapple
  • 本文由 发表于 2020年8月22日 06:11:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/63530644.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定