【问题标题】:ArrayList size shrinking by 1 upon each method call [duplicate]每次方法调用时,ArrayList 大小缩小 1 [重复]
【发布时间】:2016-03-16 22:12:40
【问题描述】:

快速提问。我目前正在制作一个合成除法计算器,作为其中的一部分,我需要测试 P/Q(双精度)是否可以作为方程中的一个因素(作为整数列表提供给该方法)。

这是我在主类中的代码:

public static void main(String[] args)
{
    List<Integer> coeffs = new ArrayList<>();
    coeffs.add(1);
    coeffs.add(-6);
    coeffs.add(11);
    coeffs.add(-6);
    System.out.println(coeffs); // Returns [1, -6, 11, -6]
    System.out.println(doesPqWork(coeffs, 1)); // Returns 'true' as intended
    System.out.println(coeffs); // Returns [-6, 11, -6]
    System.out.println(doesPqWork(coeffs, -2)); // Returns 'false' not as intended
    System.out.println(coeffs); // Returns [11, -6]
    System.out.println(doesPqWork(coeffs, 3)); // Returns 'false' not as intended
    System.out.println(coeffs); // Returns [-6]
}

这是 P/Q 方法本身:

private static boolean doesPqWork(List<Integer> coefficients, double PQ)
{
    List<Double> results = new ArrayList<>();
    double lastResult = coefficients.get(0);
    coefficients.remove(0);
    for(int coeff : coefficients) // 2, 1
    {
        double multiplied = PQ * lastResult;
        lastResult = coeff + multiplied;
        results.add(lastResult);
    }
    return results.get(results.size() - 1) == 0;
}

请忽略此方法如何计算它,我只是想知道为什么“coeffs”ArrayList 每次都在缩小。我已经用 Java 编码两年了,我从来没有遇到过这个问题。

我认为这是因为当我调用“coefficients.remove(0)”时,由于某种原因链接回“main”方法中的“coeffs”列表,但是当我创建一个新变量时,它不会可能链接回来它仍然会做奇怪的事情。

我知道一种方法可以通过创建一些断断续续的代码和重复变量来解决此问题,但这似乎非常浪费,我真的很想知道这种意外行为的根源,以便我可以解决它。

我可能在这里犯了一个愚蠢的错误,但如果我不是,那么有人可以向我解释到底发生了什么吗?哈哈。

【问题讨论】:

  • 我的意思是你打电话给 coefficients.remove(0) 所以,除非我遗漏了什么,否则我会认为这就是为什么......
  • 是的,但这不会只影响新的“coefficients”变量而不影响“coeffs”变量吗?我认为出于某种原因,Java 认为这两个变量是相同的,所以我创建了第三个等于“系数”的变量并使用它来代替,但同样的行为发生在“系数”变量每次收缩的地方。 “remove()”方法是否也有可能有问题?
  • 不,你有误会。您在main 中多次致电doesPqwork。每次调用它,它都在运行该方法并调用remove
  • 抱歉,我现在从下面的 par 中知道,当您将它传递给方法时,它实际上不是副本。
  • 这不是一个论坛不要编辑标题说“已解决”或将其添加到内容中。用复选标记将答案标记为正确,以表明它解决了您的问题。对正确答案和任何对您有帮助的人投赞成票,对任何不正确或无用的问题投反对票。

标签: java arraylist methods call


【解决方案1】:

Java 中的对象(例如Arrays)不作为副本传递。您的函数接收对传入参数的引用,因此当您调用 coefficients.remove(0) 时,您将删除从 main()coeffs 数组)传递的数组的第一个元素。

【讨论】:

  • 啊,谢谢。有什么方法可以让它复制而不是作为同一个对象传递?
  • 不,你绝对不应该复制数组,那是非常浪费的。将另一个参数传递给函数,该参数是您要开始扫描数组的索引,然后更改 for 循环以使用该索引作为其起点(或者根据您的需要在 1 开始循环索引你的算法做)。
  • 哦,我明白你的意思了。我会考虑到这一点。谢谢。
【解决方案2】:

因为你打电话给coefficients.remove(0)

然而,Java 是按值传递的;它将对对象的引用作为值传递。见Is Java "pass-by-reference" or "pass-by-value"?

所以在你的情况下,你传递你的 coeffs ArrayList 并且实际上是在 doesPqWork() 中操纵它。

仅仅创建一个新的引用也不会修复它。 IE。 ArrayList&lt;Integer&gt; tmp = coeffs; 只是创建另一个引用,而不是它的“副本”。

一种可能的解决方案是将您的coeffs 对象的“副本”发送到doesPqWork(),例如doesPqWork(new ArrayList&lt;Integer&gt;(coeffs), 1));

这将创建一个与coeffs 具有相同值的新对象。

How do I clone a generic List in Java? 也可能有帮助。

【讨论】:

  • 谢谢!我想我会用这个。我正在考虑使用这个: List coeffs = coefficients.subList(1, coefficients.size());但我更喜欢你的解决方案!
【解决方案3】:

啊哈!这是答案OP。

当您返回 results.get(results.size()-1) == 0; 时,.size()-1 正在缩小您的数组。这是因为当您查看代码时,您将数组列表coeffs 直接传递到该方法中并像@par 所说的那样将其更改为 b/c,您传递的是引用而不是副本。

编辑:这是修改代码的最简单方法。

public static void main(String[] args) {
        List<Integer> coeffs = new ArrayList<>();
        coeffs.add(1);
        coeffs.add(-6);
        coeffs.add(11);
        coeffs.add(-6);
        List<Integer> coeffCopy = new ArrayList(coeffs);
        System.out.println(coeffs); // Returns [1, -6, 11, -6]
        System.out.println(doesPqWork(coeffCopy, 1)); // Returns 'true' as intended
        System.out.println(coeffCopy); // Returns [-6, 11, -6]
        System.out.println(doesPqWork(coeffCopy, -2)); // Returns 'false' not as intended
        System.out.println(coeffs); // Returns [11, -6]
        System.out.println(doesPqWork(coeffCopy, 3)); // Returns 'false' not as intended
        System.out.println(coeffs); // Returns [-6]
    }

    private static boolean doesPqWork(List<Integer> coefficients, double PQ) {

        List<Double> results = new ArrayList<>();
        double lastResult = coefficients.get(0);
        coefficients.remove(0);
        for (int coeff : coefficients) // 2, 1
        {
            double multiplied = PQ * lastResult;
            lastResult = coeff + multiplied;
            results.add(lastResult);
        }
        return results.get(results.size() - 1) == 0;
    }

【讨论】:

  • 实际上,这不是问题,因为这与“结果”数组列表有关,与“系数”数组列表无关:P
  • 是的,但是该逻辑在 return 语句中,因此,当调用该方法时,它正在修改原始数组。
  • 我真的不明白你的意思。 "results.get(results.size()-1) == 0" 只通过获取arraylist中的最后一个值返回一个布尔值,这里根本没有代码来修改任何对象。
  • @Garry 这是通过引用传递的东西。
  • 是的,我把它修好了。非常感谢您的帮助。再见! :)
【解决方案4】:

你需要复制数组:

    private static boolean doesPqWork(List<Integer> coefficients, double PQ) {


    // here you need to copy the coefficients. for example:
    List<Integer> copyOfCoeffs = new ArrayList<Integer>(coefficients);

    List<Double> results = new ArrayList<>();
    double lastResult = copyOfcoeffs.get(0);
    copyOfcoeffs.remove(0);
    for(int coeff : coefficients) // 2, 1
    {
        double multiplied = PQ * lastResult;
        lastResult = coeff + multiplied;
        results.add(lastResult);
    }
    return results.get(results.size() - 1) == 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-16
    • 1970-01-01
    相关资源
    最近更新 更多