被声明为PROTECTED FINAL STATIC的矩阵为何出现意外修改?
被声明为PROTECTED FINAL STATIC的矩阵为何出现意外修改?
这问题我之前踩过坑,核心是你误解了final修饰数组的真实作用!
你声明的ID_MATRIX_OR2这类二维数组,虽然加了final static,但final在这里只保证数组对象本身的引用不会被替换——也就是说你不能把ID_MATRIX_OR2重新指向另一个新数组,但数组里面存储的Fraction对象引用,是完全可以被修改的!
结合你的场景来看:ONE_M和ZERO_M是静态final的Fraction对象,但如果Fraction是个可变类(比如它内部有可以修改数值的setter方法,或者存储数值的字段不是final的),那当你在高斯消元过程中操作identityMatrix里的元素时,其实是直接修改了ONE_M和ZERO_M这些对象的内部值!因为你的身份矩阵数组里存的都是同一个ONE_M/ZERO_M的引用,所有用到这些对象的地方都会跟着变,包括你那个静态的身份矩阵。
举个实际的例子:你第一次做矩阵逆运算时,把identityMatrix指向了ID_MATRIX_OR2,消元过程中修改了数组里某个位置的Fraction值(比如把ONE_M改成了其他数),那ID_MATRIX_OR2里对应的元素也会变成修改后的值——因为它们指向同一个对象。第二次再调用逆运算时,静态数组早就不是原来的单位矩阵了。
给你两个可行的解决方案:
- 每次生成全新的单位矩阵实例:不要直接复用静态数组,写一个工具方法,每次根据需要的大小生成全新的单位矩阵,每个位置都创建新的
Fraction对象,而不是复用ONE_M和ZERO_M的引用。比如:
public static Fraction[][] generateIdentityMatrix(int size) { Fraction[][] identity = new Fraction[size][size]; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { identity[i][j] = (i == j) ? new Fraction(1) : new Fraction(0); } } return identity; }
然后你的switch逻辑改成:
switch(n){ case 2: identityMatrix = Matrix.generateIdentityMatrix(2); break; case 3: identityMatrix = Matrix.generateIdentityMatrix(3); break; case 4: identityMatrix = Matrix.generateIdentityMatrix(4); }
- 把Fraction改成不可变类:让
Fraction的数值字段都是final的,并且不提供任何修改内部值的方法,所有需要改变数值的操作都返回一个新的Fraction实例。这样即使不小心共享了引用,也不会修改原来的对象,从根源上避免这类问题。
备注:内容来源于stack exchange,提问作者Deryl_Myrawill
相关产品推荐
相关产品推荐

