在我大学的软件开发课上,老师一直提到在测验中我们需要确保吸气剂返回的字段需要“保护”。我想她的意思是课外的任何东西都不应该改变它。她没有给出更多的解释。
例如:
class Foo {
string[] bar = <some array contents>;
public string[] getBar() {
return bar;
}
}
任何调用getBar的代码都可以修改该数组中的元素。你怎么防止这种情况发生?我假设对象本身应该能够修改数组,而不是对象之外的任何东西。
这不是作业帮助,因为测验是几周之久。我只是想更好地理解Java,因为我的老师没有很好地解释。
更新:教师不仅允许我们在场上使用protected作为访问修饰符。
答案 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允许您的子类或同一个包中的其他类修改该字段,而无需您的类知道。
唯一应该直接触及非最终字段的类是定义它们的类。
(想想如果你希望稍后在场地改变时发射一个事件会发生什么......你只能通过设置者进行所有访问......