Java 将对象传递给方法并更改属性
如果我有一个如下所示的类:Java 将对象传递给方法并更改属性,java,parameter-passing,Java,Parameter Passing,如果我有一个如下所示的类: class A { private List<B> bs = new ArrayList<B>; public List<B> getBs() { return bs; } } 当然,这样可以修改原始列表中的对象,这就是我想要的。 然而,我发现类C修改类A的listbs中对象的值是非常令人困惑的。对于另一个开发人员来说,很难看到这种方法改变值。 所以我认为我在这里所做的被认为是坏习惯,不是吗` 编写此类
class A {
private List<B> bs = new ArrayList<B>;
public List<B> getBs() {
return bs;
}
}
当然,这样可以修改原始列表中的对象,这就是我想要的。
然而,我发现类C修改类A的listbs
中对象的值是非常令人困惑的。对于另一个开发人员来说,很难看到这种方法改变值。
所以我认为我在这里所做的被认为是坏习惯,不是吗`
编写此类代码的更好方法是什么?我同意你的推理。此方法:
public void setB(B b) {
this.b = b;
this.b.ChangeValue();
}
class A {
private List<B> bs = new ArrayList<B>;
public List<B> getBs() {
return bs;
}
}
没有很好地实现。最好对其进行重构。如果这不是一个选项,它应该清楚地记录B
参数在传递给方法时被修改。如果可能的话,也应该从方法名中明确这一点。也许你可以把它命名为setAndUpdate(B)
此方法:
public void setB(B b) {
this.b = b;
this.b.ChangeValue();
}
class A {
private List<B> bs = new ArrayList<B>;
public List<B> getBs() {
return bs;
}
}
我认为我在这里所做的被认为是不好的做法,不是吗
是的,通过getter公开类的可变部分可能会产生误导,因为数据封装得不够好。更改数据没有什么错,只是以一种不会立即被视为修改的方式进行
没有通用的规则来解决这个问题。通常,应该避免直接返回类中的可变对象。相反,在适当的情况下提供getter和setter,并且不要将List
提供给调用者:
class A {
private List<B> bs = new ArrayList<B>;
public void getSizeB() {
return bs.size();
}
public B getB(int i) {
return bs.get(i);
}
public void setB(int i, B b) {
bs.set(i, b);
}
public void addB(B b) {
bs.add(B);
}
... // Add more methods as needed
}
A类{
私有列表bs=新的ArrayList;
public void getSizeB(){
返回bs.size();
}
公共B getB(国际一级){
返回bs.get(i);
}
公共空间设置(int i,B){
b.集合(i,b);
}
公共无效地址B(B){
bs.添加(B);
}
…//根据需要添加更多方法
}
这样做的目的是控制进入
列表的内容:因为没有直接访问,所以可以验证进入列表的每个B
。使用类A
的代码必须明确说明它所做的所有修改,因为它无法直接获取列表并对其执行任何操作。首先,我认为getBs()
是个坏主意,因为该方法的调用方可以清除列表或向其中添加元素,对于a
的状态,这将是一个比仅仅更改列表中某个元素的属性更严重的更改
您可以将其替换为getB(int)
,它返回该列表的第i个元素。
现在,如果B
是不可变的,那么您的工作就完成了,getB(int)
的调用者在A的状态下不能更改任何内容
如果B是可变的,您可以决定getB(int)
将返回bs.get(i)
的副本
总而言之,我将替换:
public void getBs() {
return bs;
}
两者都有
public void getB(int i) {
return bs.get(i);
}
或
当然,你也应该添加范围检查,以确保i
是一个有效的索引。看看这篇文章,公开支持列表并不一定是件坏事。许多标准集合允许您使用例如keySet或entrySet获取支持数据结构的可修改视图。如果您的不变量(如内部大小字段)必须与列表同步,则情况就不同了。@aioobe如果您有HashMap之类的数据结构,即使不使用keySet或entrySet,也可以直接更改它。作为HashMap的所有者,您可以使用它做任何您想做的事情。但是一旦你把HashMap放到你的类中,你就要小心如何允许你的类的用户操作HashMap。谢谢,问题是列表中的对象应该是可变的。这就是我想要的。然而,我的问题是如何更清楚地说明这个对象实际上是被修改的。因此,如果你有一个房子
,你应该公开一些方法,比如关闭窗口(windowId)
?我认为最好使用house.getWindow(windowId.close()
。如果房子
需要保持一个不变量,比如numberOfOpenWindows
,那当然是另一回事了,但在我看来,暴露你的部分状态并不一定是坏事。@aioobe我的回答建议a.getB(bId).doSomething()
-相当于你的房子.getWindow(windowId).close()
。我反对house.getWindows().get(windowId).close()
,而不是house.closeWindow(windowId)
。这当然取决于A
类的目的和责任。如果客户端能够修改其包含的B
s的集合,我认为最好提供一个访问B
s和文档集合的方法,该方法公开了一个支持数据结构,而不是复制几个列表方法,并简单地将它们委托给bs
列表。我想通过house.getWindow
展示的是,公开并不总是一个坏主意作为您状态一部分的可变对象。@aioobe我不介意公开可变对象甚至集合,但通常我通过其只读包装器公开集合,以保持对其中内容的控制。
public void getB(int i) {
return bs.get(i);
}
public void getB(int i) {
return new B(bs.get(i));
}