关于java:修改克隆对象

modifying cloned objects

我正在尝试修改帐户对象,但是之后更改似乎不会出现在原始列表中。也许有人能找出错误。

见下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if(aBank.getAccount(number)!=null){
                        System.out.println("Account information is listed below");
                        System.out.println(aBank.getAccount(number).toString());
                        System.out.println("Modify first name y or n");
                         answer=keyboard.nextLine();
                            if(answer.equals("Y")||answer.equals("y")){
                                System.out.println("Enter first name:");
                                firstName=keyboard.nextLine();
                                aBank.getAccount(number).getCustomer().setFirstName(firstName);

                            }
                        System.out.println("Modify last name y or n");
                        answer=keyboard.nextLine();
                            if(answer.equals("Y")|| answer.equals("y")){
                                System.out.println("Enter last name:");
                                lastName=keyboard.nextLine();
                                aBank.getAccount(number).getCustomer().setLastName(lastName);
                            }

                    }

                else{
                    System.out.println("Account not found");
                }

注意:getaccount(number)返回帐户的一个深度复制副本,getcustomer也返回一个深度复制副本。

GetAccount的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
public Account getAccount(long accountNumber ) throws Exception {
    boolean found=false;
    for(int i=0;i<accounts.size();i++){
        if(accounts.get(i).getAccountNumber().compareTo(accountNumber)==0){
            found=true;
            return accounts.get(i).clone();
        }
    }
    if (!found){
        return null;
    }
    return null;
}


简单地调用docx1〔3〕不会返回对象的深度副本。它将返回一个浅显的副本。覆盖克隆很棘手。遵循Joshua Bloch从有效Java的建议,避免使用EDCOX1×3来支持复制构造函数。

1
2
3
4
5
6
7
8
private Account(Account account) {
   this.name = account.getName();
   //etc
}

public void createCopy(Account account) {
    return new Account(account);
}

另外,为什么不将帐户集合存储在地图中,这样在复制之前就不需要遍历N个帐户?你还需要仔细阅读布莱恩的答案。


如果getAccount()返回一个稍后要修改的深度克隆,则应将其存储在变量中。如果你不这样做,每次你打电话给getAccount(),你都会得到一个新的对象。


在这种情况下,您应该得到一个帐户的副本(通过getAccount),修改它,然后将它重新插入到列表中。

正如您所指出的,您正在修改副本。那个副本本身并没有连接到您的集合中,所以当您退出作用域时会丢失它。

另一个问题是,是否修改副本并重新插入是最佳解决方案。您可能希望在适当的位置进行修改,但这会使您面临各种各样的问题(例如线程处理——如果您在修改帐户的中途,而另一个客户端遍历列表并读取帐户详细信息,会发生什么情况?)