java中的“Final”和复制2D数组

时间:2012-10-12 04:10:37

标签: java clone final multidimensional-array

我在理解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个数组,一个用于编辑,另一个将保留?

先谢谢。

5 个答案:

答案 0 :(得分:3)

您的final MYARRAY_ORIGINAL确实是只读的:您不能在类构造函数或属性声明的其他方面为MYARRAY_ORIGINAL引用分配新值:

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

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

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

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

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

最后一段代码来自这里:Immutable array in Java

答案 1 :(得分:0)

如果Objects,则final无法更改引用,但可以更改对象状态。

这就是为什么您可以更改final MYARRAY_ORIGINAL

的值的原因

答案 2 :(得分:0)

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

A类{ final int [] array;

 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

 }
}

要了解有关最终结果的更多信息,请查看最终变量Java Language Specification

答案 3 :(得分:0)

最终并不意味着'只读'本身,但更多的是“安全发布”用于其他线程,而不是它所定义的线程。“最终”的另一个目标是确保最新的对象可用于多线程环境。

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

 private final int[][] MYARRAY_ORIGINAL;

引用是“final”,但不是对象本身。理解它的更好方法是:

public static final List myList = new ArrayList();

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

在多线程场景中,我将看到最终的上下文。

奖励:要回答你的问题,你不能制作一个'只读'数组,你必须自己管理(最后,只保持'只读'来引用不是对象)

答案 4 :(得分: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); 
}

现在你不必担心从外面修改数组。