Java:递归和按值传递

Posted

技术标签:

【中文标题】Java:递归和按值传递【英文标题】:Java: Recursion and Passing by value 【发布时间】:2016-03-15 12:21:05 【问题描述】:

我对 Java 中的递归有点困惑:

public int recursion(Board board2,int x)
    Board board1 = board2;
    if(x==3)
        System.out.println("End");
        return 0;
    

    board1.fix(obj, Color.BLUE, x, 12);
    return recursion(board1, x+1);


这只是将对象放入板中的示例。如何更改board1,但不能更改我作为参数传入的原始板?由于在方法之外,我作为参数传递的Board在执行后发生了变化,我不明白为什么。我正在阅读Java通过值而不是引用传递。我想让程序在递归过程中恢复到之前的状态,而不是改变真正的板子。

编辑

我试过这样,还是不行:

public int recursion(Board board2,int x)
    try
        board1 = (Board)board2.clone();
    catch (Exception e)
        System.out.println("Error "+e);
    
    if(x==3)
        System.out.println("End");
        return 0;
    

    board1.fix(obj, Color.BLUE, x, 12);
    return recursion(board1, x+1);    

编辑 2

这是我实现克隆方法的方式

class Board extends JPanel implements Cloneable
    // ...
    @Override
    protected Board clone() throws CloneNotSupportedException    
       return(Board) super.clone();  
     
    // ...

编辑 3

我仍然无法让它工作

class Board extends JPanel implements Cloneable
    public Color[][] board; 

    @Override
    public Board clone() 
        Board board1 = new Board();
        board1.board = this.board;
        return board1;  
    
    // ...
   

【问题讨论】:

board1 包含与board2 相同的引用,因此它们指向同一个确切的对象。引用(对象的地址)按值传递。 如果对象的副本是按值传递的,那么递归对于后续调用将不起作用。 【参考方案1】:

除了@Sweeper 的回答,您的克隆方法需要执行所有成员变量的深层复制。

class Board extends JPanel implements Cloneable
    public Color[][] board; 

    @Override
    public Board clone() 

        Board newBoard = new Board();

        // perform a deep copy of the two dimensional array here - see the link below

        return newBoard;  

    


要执行二维数组的深拷贝,请参阅this SO answer。

另见this article about cloning。

或者,您可以使用“复制构造函数”,它是一个将相同类型的对象作为参数并有效复制其所有值的构造函数:

public class MyClass 

    private int someVariable;

    public MyClass(MyClass other) 
        this.someVariable = other.someVariable;
    

    ...

【讨论】:

@GioGio 我特别赞成@Jason 的回答,因为他提出了clone 方法的替代方案。我个人对这种方法没有太多经验,但这主要是因为我已经阅读了很多关于它的复杂性和失败的信息(参见Joshua Bloch's interview on the subject)。我个人不会使用clone。您还应该查看 *** 上关于 Java 的 pass by value 的另一篇文章。我认为它完美地解释了它。【参考方案2】:

本例中的值是对内存中同一对象的引用。如果你想真正回到初始点,你应该做Object.clone();

http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#clone()

 //when calling it initially:
 recursion(board.clone(), x)

【讨论】:

【参考方案3】:

在方法中,参数board2 持有与您传递给方法的参数相同的引用。我猜你不希望它是这样的。你想要一个具有相同但不同引用的板的副本,这样你对副本所做的效果不会影响你传入的参数。我说得对吗? (我能读懂你的心思!)

clone() 方法在这种情况下最好用!首先,在Board类中,实现Cloneable

public class Board implements Cloneable 


然后给它添加clone()方法。

它的实现大致是这样的:

    创建类的新实例

    将在this 中找到的所有字段分配给新实例

    返回新实例。

【讨论】:

你说得对,但还是不行,它继续改变我传递的论点。 我怀疑你是否正确地实现了clone,并且在第一次调用递归方法之前你还需要clone 对象。在方法中根本不需要更改引用。 我编辑了帖子,反正我不明白,为什么我必须在递归方法之前克隆它? @GioGio 你的克隆方法是错误的——它不应该调用 super.clone()。按照上面的说明正确实施。 @GioGio 也许你应该试试board1.board = this.board.clone();

以上是关于Java:递归和按值传递的主要内容,如果未能解决你的问题,请参考以下文章

(转)Java:按值传递和按引用传递详细解说

VB 参数传递:按值传递和按地址传递

Python按值传递参数和按引用传递参数

我是不是正确理解了 C 中的按值传递和按引用传递?

C/C++按值传递和按地址传递

按引用传递然后复制和按值传递在功能上是不是不同?