数组的获取器和设置器

11

我有关于数组的getter和setter几个问题。假设我们有一个像这样的类,在其构造函数中创建了一个私有副本的数组:

import java.util.Arrays;

public class Foo
{
    private int[] array;

    public Foo(int[] array) {
        this.array = Arrays.copyOf(array, array.length);
    }
}

我们希望只通过getter和setter访问/修改数组。如果我们有一个如下所示的getter:
public int[] getArray() {
    return array;
}

这会破坏getter的作用,因为我们正在返回一个引用,允许用户直接修改数组中的元素。例如:

Foo foo = new Foo(someArray);
...
int[] bar = foo.getArray();
bar[0] = 123; // Now foo.array[0] = 123 and we haven't used a setter!

所以我们需要类似这样的东西:
public int getElement(int index) {
    return array[index];
}

同样适用于setter。但是,如果我们按元素进行操作,我们还需要提供一种获取长度的方法:
public int getArrayLength() {
    return array.length;
}

对于一维数组来说,这已经有点混乱了,但如果我们有一个多维数组的话:

import java.util.Arrays;

public class Foo
{
    private int[][][] array;

    public Foo(int[][][] array) {
        // Code for making a deep copy here
    }

    public int getElement(int i, int j, int k) {
        return array[i][j][k];
    }

    public void setElement(int i, int j, int k, int value) {
        array[i][j][k] = value;
    }

    public int getArrayLength() {
        return array.length;
    }

    public int getArrayLength(int i) {
        return array[i].length;
    }

    public int getArrayLength(int i, int j) {
        return array[i][j].length;
    }
}

对于这样一个微不足道的任务,这是大量的代码,更重要的是实际使用起来很混乱。我们真的必须最终得到这样的东西吗?还是有更好的方法来完成它?我已经到处寻找,似乎没有针对这个问题的“标准实践”。

4个回答

10

多维数组也是一维数组:int[a][b][c]实际上就是int[a*b*c],所以问题归结为如何安全地提供访问?只需像这样:

public class Foo {
    private int[] array;

    public Foo(int[] array) {
        this.array = Arrays.copyOf(array, array.length);
    }

    /** @return a copy of the array */
    public int[] getArray() {
        return Arrays.copyOf(array, array.length);
    }
}

就是这样。

调用者拥有一个安全的数组副本,并且可以像正常使用数组一样使用它。不需要使用委托方法。


如果数组为空怎么办?它会抛出空指针异常吗? - Brooklyn99
@Brooklyn99 如果数组可能为空,则应该做好相应处理:return array == null ? null : Arrays.copyOf(array, array.length); - Bohemian

1
关于第一部分,您的getter是不是可以像构造函数那样?
public int[] getArray() {
    return Arrays.copyOf(array, array.length);
}

1
你认为 ArrayList 或者它之前的 Vector 是做什么用的?
我认为更好的问题是,为什么在这个时候你要暴露出 Foo 实际上是由一个数组支持的呢?如果你想要封装它,你不需要在各个地方都有访问器和设置器。如果你只是想要创建一个类包装器来包装这个数组,那么我建议你有一个接口,叫做 IntList 或其他名称,并使 Foo 成为由列表支持的具体实现。

0

我为多维通用数组编写了一个小型API。您可以获得每个元素的getter和setter,无论您的维度是什么。

在github上查看MDDAJ

以下是一个示例:创建一个5维字符串数组:

MDDAPseudo<String> c = new MDDAPseudo<String>(10,20,5,8,15);
c.set("xyz", 0,0,2,1,0); // setter indices: [0][0][2][1][0]
String s = c.get(0,0,0,0,0); // getter indices [0][0][0][0][0]

Bohemian已经告诉你可以只使用一个维度。在这种情况下,类PDDAPSeudo内部也只有一个维度。但是API提供了像多维数组一样的访问方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接