Java传递的价值澄清了

时间:2016-01-16 22:06:10

标签: java cell pass-by-value

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

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;

}

我在这里读了一些关于java的帖子,但显然我仍然没有100%抓住它。

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

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

编辑:

我认为我不明白它何时称为属性,哪些不称为属性。 如果你称之为“新”,我会有所不同。

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

例如:

public class Board  { //fake class

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

和另一个班级:

    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因为在堆中创建因为它是board对象的一部分所以需要它这两种情况都没有改变?

3 个答案:

答案 0 :(得分:5)

记住它的最好和最不容易的方法如下: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);

答案 1 :(得分:4)

对象的引用按值传递,这意味着

boardGame = new Cell[8][8];

没有任何伤害,但改变你从boardGame获得的任何东西。

答案 2 :(得分:2)

Java基本上总是" 按值传递"。

  

警告:它传递存储在变量的内存中的值。

     

对于原始数据类型,内存在堆栈空间中分配,而对于对象,引用内存在堆栈空间中分配,但对象本身在堆中创建。类似的情况也可以用于数组,尽管它们并不是强烈意义上的对象。

下面的图表会更清楚。

Stack and Heap memory space

Array Allocation

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

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

我还想提请你注意代码的事实

boardGame[7][7] = c;

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

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

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