[英]The best practice using clone in an aggregated class
我有一个系统,其中有一个客户,其补充的ArrayList作为其属性。
客户类的代码是:
public class Customer implements Cloneable
{
.
.
ArrayList<Supplement> suppList
public Customer(String fName, String lName, String emailInput, ArrayList<Supplement> list)
{
setFName(fName);
setLName(lName);
setEmailAddr(emailInput);
setSuppList(list);
}
public void setSuppList(ArrayList<Supplement> list)
{
suppList = new ArrayList<Supplement>();
for(Supplement sp : list)
{
suppList.add(sp);
}
}
}
public ArrayList<Supplement> getSuppList() throws CloneNotSupportedException
{
ArrayList<Supplement> list = new ArrayList<Supplement>();
if (suppList != null)
{
for(Supplement sp : suppList)
{
list.add((Supplement)sp.clone());
}
}
return list;
}
public void addSupp(Supplement item)
{
suppList.add(item);
}
public void removeSupp(Supplement item)
{
suppList.remove(item);
}
最初,我的setSuppList方法仅包含一行代码,即suppList = list,而我的getSuppList方法只是“ return suppList”。 我觉得这是一次隐私泄漏,因此我在这两种方法中都称为克隆。 对于setSuppList,suppList = new ArrayList()并遍历参数列表并克隆每个对象,并将其添加到suppList数组中。 对于getSuppList,它遍历suppList并克隆其中的每个Supplement对象,将其添加到新数组中并返回该数组。 但是,我意识到,如果将补充对象的价格从$ 3更改为$ 50,并且如果我有100个客户,则意味着我必须继续调用setSuppList()100x。
我改变了主意,因此将setSuppList方法更改为suppList = list,并将克隆内容仅保留在getSuppList中。
然后想到了...为什么我不将suppList作为setSuppList中的新数组,并将参数“ list”中的每个项目添加到suppList中。 这样,list和suppList都引用相同的对象,但是当list删除一个项目时,Customer对象的suppList保持不受影响。 只是当单个项目受到影响时,suppList才会相应更新(例如,补充价格),并且当我想在suppList中添加或删除项目时,可以使用addSupp方法或removeSupp方法或setSuppList方法。
public static void main(String[] args)
{
try
{
Supplement s1 = new Supplement("A", 2.9);
Supplement s2 = new Supplement("B", 3);
ArrayList<Supplement> spList = new ArrayList<Supplement>();
spList.add(s1);
spList.add(s2);
Customer cstmr = new Customer("killua", "zoldyck", "killua@gmail.com", spList);
ArrayList<Supplement> spList2 = cstmr.getSuppList();
System.out.println("cloned array size : "+spList2.size());
spList2.remove(0);
System.out.println("After removing an item in the cloned array");
System.out.println("cloned array size : "+spList2.size());
System.out.println("Array returned from getSuppList size : "+cstmr.getSuppList().size());
spList.remove(0);
System.out.println("array size : "+cstmr.getSuppList().size());
System.out.println("");
spList.get(0).setWeeklyCost(50);
System.out.println("If I change the first item in the first array prize to 50");
System.out.println("price of 1st item in object in the first array : "+spList.get(0).getWeeklyCost());
System.out.println("price of 1st item in object in the array returned by getSuppList : "+cstmr.getSuppList().get(0).getWeeklyCost());
System.out.println("");
s1.setWeeklyCost(40);
System.out.println("If I change the supplement object directly to 40");
System.out.println("price of 1st item in object in the first array : "+spList.get(0).getWeeklyCost());
System.out.println("price of 1st item in object in the array returned by getSuppList : "+cstmr.getSuppList().get(0).getWeeklyCost());
}
catch(CloneNotSupportedException e)
{
}
}
输出量
克隆数组大小:2
删除克隆数组中的项目后
克隆数组大小:1
从getSuppList返回的数组大小:2
数组大小:2
如果我将第一组奖品中的第一项更改为50
第一个数组中的对象的第一项价格:50.0
getSuppList返回的数组中对象中第一项的价格:2.9
如果我直接将补充对象更改为40
第一个数组中的对象的第一项价格:50.0
getSuppList返回的数组中对象中第一项的价格:40.0
但是,当我尝试这样做时,会有意外的行为。 spList.get(0).setWeeklyCost(50); 不会影响Customer对象的suppList对象。
怎么可能? spList和suppList都引用相同的对象,尽管它们是不同的数组。
由于Supplement
是其自身的东西,与Customer
完全不同,并且可以自己重命名和重新定价,因此您永远不应将其克隆为Customer
逻辑的一部分。
您应该“克隆” 列表 ,因为那是客户的属性,可以通过调用copy-constructor轻松完成:
suppList = new ArrayList<>(list);
spList.get(0).setWeeklyCost(50); 不会影响Customer对象的suppList对象。 怎么可能 ??
因为当您调用cstmr.getSuppList()
时仍在克隆Supplement
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.