Java 阐明了按值传递

Java pass by value clarified

我有一个 Cell 对象列表,表示棋盘内的棋盘游戏 class。

Cell boardGame[][] = new Cell[8][8];

我需要一个临时单元格来尝试玩家在他身上移动并将其与其他单元格进行比较,所以我认为我可以使用 java 传递值来完成它。

test(board.boardGame);
board.printBoard(); 

private static void test(Cell[][] boardGame) {
Cell c = new Cell((new Soldier(ChessPiece.QUEEN, Color.WHITE)), 7, 4);
    boardGame[7][7] = c;

}

我在这里阅读了一些 post 关于 java 的内容,但显然我仍然没有 100% 理解它。

我原以为棋盘上只有一个白皇后,但我看到了两个。 我知道如果你传递一个引用你可以改变它的值,但我认为如果我传递数组本身它的成员将不会被修改除非我执行 return.

请帮助我更好地理解这个主题。 谢谢

编辑:

我想我不明白它什么时候调用属性,什么地方不调用。 如果你打电话给 "new" 或不打电话,我会有所不同。

当它是另一个对象的一部分时它称为属性对吗?但是每个对象都可以作为另一个对象的一部分创建。我可以在狗 class 中创建一个新字符串,然后在动物 class 中创建狗 class,然后在另一个 class 中创建它。所以只有顶部 class 在堆栈中?

例如:

public class Board  { //fake class

    int num= 0;
    public void test(int i){
        i = 1;
    }
}

在另一个 class 上:

    public class Main {
        static void outsideTest(Board board){
            board.num = 1;
        }
    public static void main(String[] args) {
        Board board = new Board();
        System.out.println(board.num);
        board.test(board.num);
        System.out.println(board.num);
        outsideTest(board);
        System.out.println(board.num);
}
}

现在我不明白为什么在 test() 方法上 num 没有改变,而在 outsideTest() 上 num 改变了,num 是在堆中创建的,因为它是板对象的一部分,所以它需要在这两种情况下都要更改否?

对象的引用是按值传递的,也就是说

boardGame = new Cell[8][8];

不会造成任何伤害,但改变您从 boardGame 获得的任何东西就会造成伤害。

最好和最容易记住的方法如下:Java 按值传递所有内容,包括引用。 :)

当你有一个变量时:

Object a = new Object();

您实际上并没有在 a 中存储对象。你所拥有的是对内存中某处对象的引用。

同样,当您在对象上调用方法时:

String b = a.toString();

你不会那样做。你所说的是一个方法,它使用引用对象的数据作为它的上下文。

所以当你传递一个对象作为参数时

System.out.println(b);

您没有传递整个对象。您传递引用,该引用按值传递。

编辑:

如果引用不是按值传递,而是按引用传递,你可以做这样的事情,幸运的是你不能。

public void swap(Object a, Object b){
   Object swap = a; a = b ; b = swap;
} 

String a = "a";
String b = "b";
swap(a,b);

// would print "b a" if references were 
// passed by reference but instead prints 
// "a b" as they're passed by value.
System.out.println(a + " " b);

Java 本质上总是“pass-by-value”。

Caveat: It passes the value stored in the memory for the variable.

For primitive data types, the memory is allocated in stack space, whereas for objects reference memory is allocated in stack space but the object itself is created in heap. Similar can be stated for arrays too though they are not exactly objects in a strong sense.

下图会更清楚。

您的 Cell 对象 2D 数组应该看起来像 anObjectArrayVar(不完全是图表中指向对象的 ref 现在应该指向行,我们需要另一个每行的 ref 和对象之间的堆分配级别(一组引用对象的单元格)。

因此,当您传递 boardGame 时,将传递存储在堆栈中的值,该值存储对 对象数组 的引用(就像存储在 anObjectArrayVar 中的值一样)。如果说 refs 列表存储在编号为 50 的位置,那么 anObjectArrayVar 会存储它,并在我们调用它时将该值传递给测试方法。在这种情况下,测试方法将无法转到内存位置 anObjectArrayVar 并更改其值(比如 100),因为它只有该值的副本,但它可以轻松地(直接或间接)更改它所指的值,例如值在 ref 或下一级(并添加新对象,就像在您的情况下添加一个带有皇后的新单元格)或它们指向的对象,这些更改将反映在整个程序中!

我还想提醒您注意代码

boardGame[7][7] = c;

将替换当前单元格(以及当前单元格中的士兵),如果游戏中那个地方最初有一个士兵,这将产生重大问题。游戏状态实际上会改变。

作为一个建议(考虑到对您的设计的了解有限)我会说至少在替换之前将单元格保存在测试方法中的其他值中。

Cell old = boardGame[7][7];
//now do all your operations
boardGame[7][7] = old;//just before returning from the function