1

我在理解 Java 中“final”的概念时遇到了一些麻烦。

我有一堂课如下:

 public class MyClass 
 {
     private int[][] myArray; // intended to be changed
     private final int[][] MYARRAY_ORIGINAL; // intended to be unchangable

     public MyClass(int[][] array) 
     {
        myArray = array;
        MYARRAY_ORIGINAL = array;
     }

 }

我的理解是“最终”将使 MYARRAY_ORIGINAL 只读。但我尝试过编辑 myArray,它也编辑了 MYARRAY_ORIGINAL。我的问题是,在这种情况下,“最终”究竟是做什么的?为了获得额外的荣誉,我如何将通过构造函数传递的数组复制到 MYARRAY_ORIGINAL 中,以便我可以拥有 2 个数组,一个要编辑,一个将保留?

提前致谢。

4

5 回答 5

3

final MYARRAY_ORIGINAL确实是只读的:MYARRAY_ORIGINAL除了类构造函数或属性声明之外,您不能为引用分配新值:

public void someMethod() {
    //it won't compile
    MYARRAY_ORIGINAL = new int[X][];
}

数组中的值不是最终值。这些值可以在代码中随时更改。

public void anotherMethod() {
    MYARRAY_ORIGINAL[0][0] = 25;
    //later in the code...
    MYARRAY_ORIGINAL[0][0] = 30; //it works!
}

如果您确实需要一个最终元素列表,换句话说,一个无法修改其元素的列表,您可以使用Collections.unmodifiableList

List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));

最后一段代码取自这里:Java中的不可变数组

于 2012-10-12T04:13:34.113 回答
0

在 的情况下Objectsfinal使引用无法更改,但可以更改对象状态。

这就是您能够更改值的原因final MYARRAY_ORIGINAL

于 2012-10-12T04:12:17.220 回答
0

MYARRAY_ORIGINAL确实是只读变量。不能为您的数组引用分配新值,也不能更改数组的长度。最终变量初始化可以推迟到构造函数被调用。如果尝试修改 final 变量的引用,编译器将抛出错误消息。但有可能的是,可以编辑 和 的元素,MYARRAY_ORIGINALmyArray可以更改分配给最终变量的对象的状态。例如

A 类 { final int[] 数组;

 public A() {
  array = new int[10] // deferred initialization of a final variable
  array[0] = 10;
 }

 public void method() {

 array[0] = 3; // it is allowed

  array = new int[20] // not allowed and compiler will throw an error

 }
}

要了解有关 final 的更多信息,请查看有关 final 变量的Java 语言规范。

于 2012-10-12T04:22:05.753 回答
0

Final 本身并不意味着“只读”,而对于其他线程来说,“安全发布”而不是定义它的线程。“final”的另一个目的是它确保在多线程中可用的最新对象环境。

其次,如果您将某些内容定义为“最终”,例如:

 private final int[][] MYARRAY_ORIGINAL;

引用是“最终的”,但不是对象本身。更好的理解方式是:

public static final List myList = new ArrayList();

现在我可以从任何其他线程访问 myList - 我可以修改它(添加到它);但我不能 (a) 再次声明它 - myList = new ArrayList(); (b) 为其分配另一个列表 - myList = anotherList;

在多线程场景中,我认为 final 的上下文最好。

奖励:要回答你的问题,你不能制作一个“只读”数组,你必须自己管理它(作为最终,只维护“只读”来引用而不是对象)

于 2012-10-12T04:25:08.530 回答
0

您可以使用该方法System.arraycopy制作数组的副本,如下所示 -

int[][] source = {{1,2},{3,4}};
int[][] copy = new int[source.length][];
System.arraycopy(source, 0, copy, 0, source.length);

此外,您的代码对您正在尝试做的事情有一些问题。如果你看构造函数

public MyClass(int[][] array) { //something else passes the array
    myArray = array;
    MYARRAY_ORIGINAL = array; // you are just keeping a reference to it can be modified from outside
}

如果您真的不希望任何人修改该数组中的值MYARRAY_ORIGINAL,您应该复制来自外部的源数组。

public MyClass(int[][] array) { 
    myArray = array; //make a copy here also if you don't want to edit the argument array
    MYARRAY_ORIGINAL = new int[array.length][];
    System.arraycopy(array, 0, MYARRAY_ORIGINAL, 0, array.length); 
}

现在您不必担心从外部修改数组。

于 2012-10-12T04:30:34.597 回答