带有“用户定义类型”的可变长度参数列表搞乱了参数

时间:2013-09-20 22:14:31

标签: java variadic-functions

自从我提出第一个问题以来,我已经走了很长一段路,用网格布局编写了一个tictactoe游戏,按钮推动制作x和o并声明获胜者和执行复数运算的类< em>(例如,z1 = -3-4i加上z2 = 7 + i通过cAdd(z1,z2))并且正确地计算(例如,sin(z1)和log(z2))。 (通过名为 Derive 的CAS的帮助确认并实施。)

到目前为止没问题。

所以我决定增强cAdd以接受两个以上的复数(例如,cAdd(z1,z2,z3)),并为变长参数列表找到以下语法:

public ComplexNumber cAdd ( ComplexNumber ... a);

但是cAdd(z1,z2)的双参数版本工作正常,“varargs”版本(例如,cAdd(z1,z2,z3))给出了正确的结果但更改了参数值,因此如果z1是在以后的计算中使用,它不是它最初的开始。

这是代码,然后是输出。

  class ComplexNumber {

    double real, imag;

    public ComplexNumber() {                // default constructor
    }

    public ComplexNumber(double a, double b) {    // initializer constructor
        real = a;
        imag = b;
    }

  public class CBug {

    public static void cPrint(String s, ComplexNumber z) {
        System.out.println(s + z.real + " + " + z.imag + "i");
    }

    public static void dump(int n, ComplexNumber z, ComplexNumber [] a){
        System.out.print("Dump " + n + "; sum so far is " );
        cPrint("z = ", z);
        for (int i = 0; i < a.length; i++)
            cPrint("" + i + ": " ,a[i]);
        System.out.println("");
    }

    public static ComplexNumber cAdd(ComplexNumber ... a) {
        ComplexNumber z = a[0];
        for (int i = 1; i < a.length; i++){
            dump(i,z,a);
            z.real = z.real + a[i].real;
            z.imag = z.imag + a[i].imag;
        }
        dump(99,z,a);
        return z;
    }

    public static void main(String[] args) {
        ComplexNumber sum = new ComplexNumber();
        ComplexNumber z1 = new ComplexNumber(1000,500);
        ComplexNumber z2 = new ComplexNumber(7, 1);
        ComplexNumber z3 = new ComplexNumber(100,100);
        cPrint("z1 = ", z1);
        cPrint("z2 = ", z2);
        cPrint("z3 = ", z3);

        System.out.println("");

        System.out.println("++++++++++++++++++++++");
        sum = cAdd(z1,    z2,    z3) ;
        cPrint     ("z1 + z2 + z3 = " , sum);
        System.out.println("--------------------");

        cPrint("z1 = ", z1);
        cPrint("z2 = ", z2);
        cPrint("z3 = ", z3);
    }
  }

输出:

run:
z1 = 1000.0 + 500.0i
z2 = 7.0 + 1.0i
z3 = 100.0 + 100.0i

++++++++++++++++++++++
Dump 1; sum so far is z = 1000.0 + 500.0i   [correct]
0: 1000.0 + 500.0i
1: 7.0 + 1.0i
2: 100.0 + 100.0i

Dump 2; sum so far is z = 1007.0 + 501.0i     [correct]
0: 1007.0 + 501.0i        [but WHY DID ARG[0] CHANGE to "z so far"?]
1: 7.0 + 1.0i
2: 100.0 + 100.0i

Dump 99; sum so far is z = 1107.0 + 601.0i   [correct]
0: 1107.0 + 601.0i         [WHY DID ARG[0] CHANGE AGAIN to new "z so far"?]
1: 7.0 + 1.0i
2: 100.0 + 100.0i

z1 + z2 + z3 = 1107.0 + 601.0i                [correct]
--------------------
z1 = 1107.0 + 601.0i          [WHY DID z1 (a.k.a. arg[0]) CHANGE?]
z2 = 7.0 + 1.0i
z3 = 100.0 + 100.0i
BUILD SUCCESSFUL (total time: 0 seconds)

由于cAdd损坏了它,因此无法在后续计算中使用第一个参数。

=============================

以下是我现在对cAdd的看法(因为我原来的“修复”[在下面的评论中描述]有点怪]:

 public static ComplexNumber cAdd(ComplexNumber ... a) {
    ComplexNumber z = new ComplexNumber();
    for (int i = 0; i < a.length; i++){
      z.real += a[i].real;
      z.imag += a[i].imag;
    }
    return z;
  }

===============================

1 个答案:

答案 0 :(得分:2)

z中创建变量cAdd时,请将其引用至a[0]。现在,za[0]都指向同一个对象。然后你改变它。

您应该做的是复制z的第一个元素,以便在修改z时,不要修改a[0]。像这样:

ComplexNumber z = new ComplexNumber(a[0].real, a[0].imag);