【问题标题】:Return void messing up reference parameter value返回 void 弄乱参考参数值
【发布时间】:2012-12-12 23:56:01
【问题描述】:

我编写此代码的目的是每次调用recurse() 时都会增加链。但是,每次recurse() 达到返回值时(根据我在调试器中看到的情况),它都会这样做;它会减少b 的值。如果您想了解我正在尝试做的事情的背景,这是项目 euler #14。

http://projecteuler.net/problem=14

private static void euler14()
{
    int currentstart=1000000;
    int longest = 0;
    int current=0;
    Integer chain=0;
    for(int i = currentstart; i>0; i--)
    {
        recurse(i,chain);
        if(chain > current)
        {
            current=chain;
            longest=i;
        }
        chain = 0;
    }
    System.out.print("Euler 14: " + longest + "\n");
}

private static void recurse(int a, Integer b)
{
    b++;
    if(a==1)
    {
        return;
    }
    else if(a%2==0)
    {
        recurse((a/2), b);
    }
    else if(a%2==1)
    {
        recurse(((a*3)+1), b);
    }
    return;

}

【问题讨论】:

  • 我找不到问题。无论如何,这个recurse(i,chain); 永远不会改变chain 的值,因为Integer 是不可变的。我想你认为recurse() 内部的b++; 会改变它,但这只会影响局部变量b;

标签: java return pass-by-reference void


【解决方案1】:

虽然对Integer 的引用(按值)传递给recurse,但对象本身是不可变的。当您执行b++ 时,递增的值将分配给b,它是recurse 的本地值。一旦您返回,该值就会返回到调用者中b 的未更改副本。

您可以将b 设为static int 变量,并将其从recurse 的参数列表中删除以解决问题:

private static int b = 0;
private static void recurse(int a) {
    b++;
    if(a==1) {
        return;
    }
    if(a%2==0) {
        recurse((a/2), b);
    } else if(a%2==1) {
        recurse(((a*3)+1), b);
    }
}

【讨论】:

  • 确实如此。有关不可变对象主题的进一步阅读:docs.oracle.com/javase/tutorial/essential/concurrency/…
  • 我尝试将chain 设为静态,并将recurse() 中b 的所有实例替换为chain。我收到错误Illegal Modifier for variable chain, only final is permitted. 似乎我只能在方法之外使其成为静态。我有一个按顺序执行所有 euler 问题的 main 方法,所以我不希望在 euler14 之外添加任何与 euler14 相关的代码,除非它是初始调用。
  • @JamesRoberts 一个较差的替代方案是将int[1] 数组作为b 传递,而是递增b[0]++。数组是可变的,所以你不需要静态变量。最后,另一种选择是使用AtomicInteger,这是一个包装int 的可变类并在其上提供线程安全操作(当然您不需要任何线程安全)。
【解决方案2】:

为了在您的 main 方法中查看对 b 的更新,您需要在递归结束时将其返回:

private static int recurse(int a, int b) {
    b++;
    if(a==1) return b;
    else if(a%2==0) return recurse((a/2), b);
    else if(a%2==1) return recurse(((a*3)+1), b);
    return b;
}

在您的主要方法中,您使用新值更新您的 chain

chain = recurse(i,chain);

【讨论】:

  • 完美。我希望我早点看到这个答案。
【解决方案3】:

由于您的方法当前没有返回值,因此您可以使用返回值来表示步数。只需在每个递归步骤中加 1:

private static int recurse(int a) {
    if(a==1) {
        return 1;
    }
    if(a%2==0) {
        return 1 + recurse(a/2);
    } else if(a%2==1) {
        return 1 + recurse((a*3)+1);
    }
}

【讨论】:

  • b现在指的是什么?
  • @jalynn2:我的错误,已删除:)
猜你喜欢
  • 2017-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-05
  • 2021-11-14
  • 2011-04-06
  • 1970-01-01
  • 2010-10-17
相关资源
最近更新 更多