我正在学习Java,我对此有些怀疑。 如果定义了带有私有变量(如
)的类class test<A>{
private A var;
...
public A get(){
return var;
}
}
get方法错误吗? 我想是因为有了这个定义,我可以像这样修改变量“ var”
test<A> x = new test<A>();
A temp = x.get();
temp.set(*something*);
最后x改变了(我使用Vector作为A对其进行了测试)。如果我理解正确,那么这行得通是因为对象引用(我错过了C指针,sob)。我错了吗?也许我不明白关键字“私人”的目的!预先感谢!
编辑:“按引用传递”和“按值传递”没有问题。我有疑问为类中的私有变量定义get()方法(您不说吗?)。请停止链接Is Java "pass-by-reference" or "pass-by-value"?
答案 0 :(得分:3)
如果您的getter方法正在返回对可变对象的引用,则这将大大削弱类提供的封装的质量,因为无需调用a即可修改类实例的状态。类的方法。
防止这种问题的一种标准策略是J. Bloch所说的防御性副本(有效Java,第3版,条款50:“在需要时制作防御性副本”)。
这意味着在getter方法中创建var
的副本,然后返回该副本。如何执行此操作取决于A
的设计。
由于A
是一个类型参数,因此要复制实例,需要在设计中提供其他支持。要了解如何使用Java的克隆机制来实现此目的,请参阅我的answer帖子“创建Copyable
类型的接口而不是使用Cloneable
有意义吗?”。
答案 1 :(得分:0)
如果遇到问题,您可以创建一个外观来保护您的变量
public class Facade extends A {
A myObj;
public Facade (A obj) {
myObj =
}
public A get(){
return myObj.get();
}
public B set(Object val) {
throw new RuntimeException("Setting is not allowed");
}
}
答案 2 :(得分:0)
这可能只是一开始的细节,但是您可以复习类java.util.concurrent.atomic.AtomicReference<V>
,这与您的示例非常相似。
通常,将实例变量放在私有变量中,同时使用getter和setter提供对变量的访问,这是标准做法。
请注意,您的类名应大写,类型参数“ V”更标准,变量名通常为“值”。另外,尝试为班级选择一个更具交流性的名称。 (类型参数类型变量可以是'ValueType',这将符合某些首选项。但是,单个字符类型变量名称更常见。)
public class Wrapper<V> {
private V value;
public V get() {
return value;
}
public void set(V value) {
this.value = value;
}
}
答案 3 :(得分:0)
我还要在这里补充一点:正如其他人所说的那样,您可以分发对象引用,并且可以对其进行修改,这可能很糟糕。
面向对象是将数据及其上的代码保存在一个地方。如果需要getter,请考虑getter的调用者需要做什么,以及该操作是否应该是具有数据的类上的方法。您的代码可能会遇到Feature Envy的代码味道,因为它违反了Tell, Don't Ask原则。
要解决此问题,请删除吸气剂,并根据需要引入新方法。例如,如果您有一些需要打印的数据对象,则可以将打印机传递给该对象,然后将其自身打印到给定的打印机。
如果要处理集合类(只是从您的模板参数猜测而来),则可能需要保留吸气剂,但是您可能根本不关心调用者更改值。