在查看MIT的软件构造讲义时,我发现有一个练习如下:
/** Represents an immutable right triangle. */ class RightTriangle { /*A*/ private double[] sides; /*B*/ public final int hypotenuse = 2; /** Make a right triangle. * @param legA, legB the two legs of the triangle * @param hypotenuse the hypotenuse of the triangle. *C* * Requires hypotenuse^2 = legA^2 + legB^2 * (within the error tolerance of double arithmetic) */ public RightTriangle(double legA, double legB, double hypotenuse) { /*D*/ this.sides = new double[] { legA, legB }; /*D*/ this.hypotenuse = hypotenuse; } /** Get the two sides of the right triangle. * @return two-element array with the triangle's side lengths */ public double[] getAllSides() { /*E*/ return sides; } /** @param factor to multiply the sides by * @return a triangle made from this triangle by * multiplying all side lengths by factor. */ public RightTriangle scale(double factor) { return new RightTriangle(sides[0]*factor, sides[1]*factor, hypotenuse*factor); } /** @return a regular triangle made from this triangle. * A regular right triangle is one in which * both legs have the same length. */ public RightTriangle regularize() { double bigLeg = Math.max(side[0], side[1]); return new RightTriangle (bigLeg, bigLeg, hypotenuse); } }
这里说E处是有问题的代码,即
public double[] getAllSides() { /*E*/ return sides; }
乍一看这里返回了一个原来的引用,可能导致表示泄露。但是又一想,double是不可变类型啊!这里即使改变了原来的double,但是return出去的double也不是原来那个double了,为什么会说代码有问题呢?
为了证实我的判断,我写了下面的一段代码:
package hetest; public class fianltest { private int ints; public int returnints() { return this.ints; } public fianltest (int ints) { this.ints=ints; } public static void main(String args[]) { fianltest f=new fianltest(2); int g=f.returnints(); g=g+1; System.out.println(f.returnints()); } }
这段代码运行结果是2,即没有改变原来的int,那说明double确实也是不可变的,问题出在哪呢?
这时我突然想起来,这里实际上返回的是double数组,那double数组是不是可变的呢?我打算自己验证一下。于是有了下面的代码:
package hetest; public class fianltest { private int [] ints; public int[] returnints() { return this.ints; } public fianltest (int[] ints) { this.ints=ints; } public static void main(String args[]) { int [] i=new int[] {2}; fianltest f=new fianltest(i); int[] g=f.returnints(); g[0]=3; System.out.println(f.returnints()[0]); System.out.println(g[0]); } }
这段代码的运行结果是3,3.这也说明了,这里对数组别名的更改影响到了内部表示,也就是说double数组是可变的!