在Java中,防止在实例方法返回后更改字段

时间:2009-02-16 05:18:01

标签: java

在我大学的软件开发课上,老师一直提到在测验中我们需要确保吸气剂返回的字段需要“保护”。我想她的意思是课外的任何东西都不应该改变它。她没有给出更多的解释。

例如:

class Foo {
    string[] bar = <some array contents>;

    public string[] getBar() {
        return bar;
    }
}

任何调用getBar的代码都可以修改该数组中的元素。你怎么防止这种情况发生?我假设对象本身应该能够修改数组,而不是对象之外的任何东西。

这不是作业帮助,因为测验是几周之久。我只是想更好地理解Java,因为我的老师没有很好地解释。

更新:教师不仅允许我们在场上使用protected作为访问修饰符。

6 个答案:

答案 0 :(得分:8)

您要么使用集合并将其包装在Collections.unmodifiable *()中,要么在防御性地复制数组,集合或对象,如果它的可变(总是数组)。

例如:

class Foo {
    private String[] bar = <some array contents>;

    public String[] getBar() {
        return bar == null ? bar : Arrays.copyOf(bar);
    }
}

你需要注意的是,这是一个浅层副本(克隆版也是如此)。不确定老师的克隆问题是什么。

答案 1 :(得分:5)

只是要添加到之前的答案之一,您希望确保使用集合而不是使用clone()方法来实现您在此处尝试实现的目标。这仅创建集合的浅表副本,集合副本中包含的所有对象引用仍指向与原始对象相同的对象,例如,即使原始集合不能,也可以修改集合副本中的对象。如果您正在尝试这样做,请确保您正在复制已归还的集合。

答案 2 :(得分:3)

我怀疑她的意思是字段本身的可见性应该是protected(或private),以便只能通过getter进行访问。对于集合,您可能还希望按照@cletus的建议进行操作,如果您不希望在类外修改它,则返回该集合的副本。 编辑根据您的编辑,她可能意味着两者。

class Foo {
    protected string[] bar = <some array contents>;

    public string[] getBar() {
        return bar;
    }
}

答案 3 :(得分:1)

要保护该字段不被更改,您需要首先将其设为私有,并且不提供任何其他更改该字段的方法的setter。这样,没有人可以更改该变量的引用。

如果该字段是可变对象,则可以再次更改其值。为此,您需要在返回该对象之前进行深度克隆。

答案 4 :(得分:1)

我要添加到cletus的第一个建议 - 使bar不可变的最简单方法是使用List而不是数组并将其包装在unmodifiableList中。这样,该类的客户端立即明白bar的内容无法更改 - 抛出UnsupportedOperationException。搞乱深度克隆可能效率很低,取决于对象的复杂性,并且仍然会返回一堆可变对象 - 只是Foo会忽略对这些对象所做的任何更改。

class Foo {
  private List<String> bar = new ArrayList<String>();
  public Collection<String> getBar() {
    return Collection.unmodifiableList(bar);
  }
}

(也可能值得注意的是,对于Java 5+中的泛型,列表的行为更像是一个数组,而不是以前的。)

答案 5 :(得分:1)

请告诉教授,所有非最终字段必须 私有才能保留封装。

Protected允许您的子类或同一个包中的其他类修改该字段,而无需您的类知道。

唯一应该直接触及非最终字段的类是定义它们的类。

(想想如果你希望稍后在场地改变时发射一个事件会发生什么......你只能通过设置者进行所有访问......