在C ++中,我可以定义一个 accessor 成员函数,该函数返回私有数据成员的值(或引用),这样调用者就无法以任何方式修改该私有数据成员。 / p>
有没有办法在Java中执行此操作?
若然,怎么样?
我知道final
关键字但AFAIK,当应用于方法时:
但它不会限制方法返回对数据成员的引用,以致调用者无法修改它。
我忽略了一些显而易见的事情吗?
答案 0 :(得分:21)
Java中没有等同于C const
“类型修饰符”(遗憾的是)。
最接近的是在可变对象周围返回不可变对象或不可变包装。
不变性不是Java的语言特性,因此您将不得不依赖于库。
不可变对象的示例是:
Integer
,Character
,.. String
File
URL
常用的不可变包装器(即防止突变的可变类型的包装器)是the Collecton.unmodifiable*()
methods返回的包装器。
答案 1 :(得分:7)
这在java中不存在。 final
和const
具有不同的语义,除非应用于基本类型的变量。 java解决方案通常涉及创建不可变类 - 其中对象在构造中初始化,并且不提供允许更改的访问器。这类的例子可以是例如String
或Integer
。
答案 2 :(得分:5)
您要么返回immutable对象,要么返回私有实例变量的副本。这样,对象的内部状态就会受到“保护”而无法修改,即:
private MyMutableObject mutable = ...
public MyMutableObject getMutableObject() {
return new MyMutableObject(this.mutable);
}
`
答案 3 :(得分:4)
你没有忽视任何事情。纯Java无法做到这一点。可能有些库使用注释提供了一些子集,但我不知道任何副手。
传递对不可变数据的引用的方式是使您传递的类不可变,简单明了。在一些非常有限但常见的情况下,有一些库函数可以帮助您生成某些数据的不可变视图。这是一个例子:
private List<String> internalData;
public List<String> getSomeList() {
return Collections.unmodifiableList(internalData);
}
答案 4 :(得分:2)
您可以返回该成员的副本,因此更改不会反映在私有引用所指向的对象中。当然,对于原语,这个问题不存在。
请注意内存使用情况!对于所有情况,这可能不是正确的解决方案。在这种情况下,另一个答案中建议的不可变对象可能是要走的路。
答案 5 :(得分:1)
我认为在Java中没有一种方法可以用于非原始对象(你总是传递对这些对象的引用)。你可以做的最接近的是返回一个对象的副本(使用克隆或类似的东西);但这不是非常惯用的Java。
我想只访问成员对象的“可见”部分,您可以做的是创建一个带有可见部分的界面,然后返回此界面。例如:
public interface Bar {
public int getBing();
}
public class BarImpl implements Bar {
private int bing;
public int getBing() {
return bing;
}
public void setBing(int bing) {
this.bing = bing;
}
}
public class Foo {
private BarImpl bar;
public Bar getNonModifiableBar() {
return bar; // Caller won't be able to change the bing value, only read it.
}
}
答案 6 :(得分:0)
取决于返回的对象以防止修改。 Java不提供对不可修改对象的声明/编译时检查,除非该类型缺少mutator。
JDK中有一些支持:像Collection.unmodifiableCollection这样的方法会创建一个对象,如果客户端调用集合mutator方法,它将抛出运行时异常。
如果您真的很有动力,可以通过定义只能自己公开/实现访问器方法的只读接口(或类)来进行编译时检查。请记住,仅仅声明方法返回只读接口不会阻止运行时修改,如果客户端使用内省并且对象提供了mutators(不抛出UnsupportedOperationException)。
答案 7 :(得分:0)
避免此问题的一种方法是不公开数据结构(另一种方法是返回副本或不可变的包装器)
e.g。而不是
public List<String> getSomeList();
有
public String getSomeElement(int index);
答案 8 :(得分:0)
当你做这样的事情时:
Object2 obj2 = obj1.getObj2();
obj2 = new Object2();
原始私有成员(obj1.obj2)仍然像以前一样(只是为了确保你掌握了这个概念)。你可以省略setter到obj2,这样就不会改变内部字段。
如果您希望Object2字段不可变,则需要应用相同的模式(私有字段,不设置setter)。
这回答了你的问题?