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

在Java中,防止字段在由实例方法返回后被更改,java,Java,在我大学的一堂软件开发课上,老师不停地提到,在一次测验中,我们需要确保获得者返回的字段需要“保护”。我猜她的意思是,课堂之外的任何东西都不能改变它。她没有给出更多的解释 例如: class Foo { string[] bar = <some array contents>; public string[] getBar() { return bar; } } class-Foo{ 字符串[]条=; 公共字符串[]getBar(){ 返回杆

在我大学的一堂软件开发课上,老师不停地提到,在一次测验中,我们需要确保获得者返回的字段需要“保护”。我猜她的意思是,课堂之外的任何东西都不能改变它。她没有给出更多的解释

例如:

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

    public string[] getBar() {
        return bar;
    }
}
class-Foo{
字符串[]条=;
公共字符串[]getBar(){
返回杆;
}
}
任何调用getBar的代码都可以修改该数组中的元素。你如何防止这种情况发生?我假设对象本身应该能够修改数组,只是不能修改对象之外的任何内容

这不是家庭作业帮助,因为测验已经进行了两周了。我只是想更好地理解Java,因为我的老师解释得不好


更新:老师不会只允许我们使用protected作为字段的访问修饰符。

您可以使用集合并将其包装在集合中。不可修改*(),或者如果数组、集合或对象的可变,您可以防御性地复制它(这些数组总是可变的)

例如:

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

    public String[] getBar() {
        return bar == null ? bar : Arrays.copyOf(bar);
    }
}
class-Foo{
私有字符串[]条=;
公共字符串[]getBar(){
返回条==null?条:Arrays.copyOf(条);
}
}

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

我怀疑她的意思是,字段本身的可见性应该受到
保护
(或
私有
),以便只能通过getter进行访问。在集合的情况下,如果不希望在类外修改集合,您可能还希望按照@cletus的建议执行操作,并返回集合的副本编辑根据你的编辑,她可能是指两者

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

    public string[] getBar() {
        return bar;
    }
}
class-Foo{
受保护字符串[]条=;
公共字符串[]getBar(){
返回杆;
}
}

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


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

为了补充前面的一个答案,您需要确保对于集合,您没有使用clone()方法来实现您在此处尝试实现的目标。这将仅创建集合的浅层副本,集合副本中包含的所有对象引用仍指向与原始集合中相同的对象,例如,即使原始集合无法修改,集合副本中的对象仍可以修改。如果您正试图这样做,请确保您正在制作一个返回集合的深度副本。

我将添加到cletus的第一个建议中-使bar不可变的最简单方法是使用列表而不是数组,并将其包装在不可修改的列表中返回。这样,类的客户机就可以立即清楚地看到,bar的内容是不能更改的——会抛出一个UnsupportedOperationException。根据对象的复杂程度,在深度克隆中乱搞可能会非常低效,并且仍然会返回一堆可变对象——只是对这些对象所做的任何更改都会被Foo忽略

class Foo {
  private List<String> bar = new ArrayList<String>();
  public Collection<String> getBar() {
    return Collection.unmodifiableList(bar);
  }
}
class-Foo{
私有列表栏=新的ArrayList();
公共集合getBar(){
返回集合。不可修改列表(条形);
}
}

(同样值得注意的是,对于Java 5+中的泛型,列表的行为比过去更像一个数组)。

请告诉教授,所有非最终字段都必须是私有的,以保留封装

Protected允许您的子类或同一包中的其他类在您的类不知道的情况下修改字段

唯一应该直接接触非最终字段的类是定义这些字段的类


(考虑一下,如果您希望稍后在字段更改时触发事件,会发生什么情况……只有通过setter进行所有访问时,您才能这样做……

bar.clone()会起作用吗?我在测验中试过,但她说不起作用,即使在我自己的代码中它似乎起作用。bar.clone()创建数组的浅拷贝。。。i、 e.新数组将引用与原始数组相同的元素。@Peter是的,但System.arraycopy()和Arrays.copyOf()也是如此,这只是一个包装器而已。可能解释是老师对此也不确定。当老师并不意味着她什么都懂。也许她的意思是这个字段必须是私有的,她不在乎你可以修改数组的元素。我猜老师想要一个深度副本。用Java制作深度拷贝的最佳方法是什么?是的,我刚才说的是这样的。另外,关于更多信息,我想我终于弄明白了。我想她只是想把所有字段都标记为最终字段。我仍然认为她没有很好地解释她想要什么。课程终于结束了,期末考试的平均成绩是56%。这表明并非所有拥有博士学位的人都应该从事教学工作。