Java 8:列表复制

6
我有一个员工对象。
我无法更新该员工对象。
public class Employee {

    public Employee(Integer id, Integer age, String gender, String fName, String lName) {
        this.id = id;
        this.age = age;
        this.gender = gender;
        this.firstName = fName;
        this.lastName = lName;
    }

    private Integer id;
    private Integer age;
    private String gender;
    private String firstName;
    private String lastName;

我最初设置了一个员工列表,但希望创建该列表的副本并对其进行更改。即使我创建了新列表,它仍然会更改原始列表。

public class ListTest {

    public static void main(String[] args) {

        List<Employee> employeeList = new ArrayList<>();
        Employee employee = new Employee(1, 1, "MALE", "TEST", "TEST");
        employeeList.add(employee);

        List<Employee> listTwo = new ArrayList<>();
        listTwo.addAll(employeeList);

        listTwo.get(0).setAge(11);

        System.out.println(employeeList.get(0).getAge());

    }
}

输出结果为11。

有没有更简单的方法从原始列表克隆,并且不应用于原始列表对象的任何更改,只应用于我创建的新列表?


1
怎么样将其变为不可变并提供一个复制构造函数? - Eugene
我已经编辑了问题。在Java中难道没有办法做到这一点吗? - Makky
1
你这样经验丰富的用户可能听说过“先做好调研工作”的建议... - GhostCat
你需要知道的是,在Java中,一切皆为对象,除了原始类型以节省内存,一切都是引用。你数组的第一个元素是同一个对象 - Daniel Cheung
��理员是为stackexchange.com工作的人。他们的工作不是提醒用户遵守本网站的政策。这也不是版主的工作。整个社区的理念是每个用户都可以自由地与任何其他用户交流...例如,提醒应该遵守的政策。我知道你不喜欢被提醒...但你刚刚收到了有用的反馈。别搞错了:如果你是一个声望值为+1的新手,你可能已经看到了很多负评,并且很可能你的问题已经被删除了。 - GhostCat
显示剩余4条评论
3个回答

12

首先在您的Employee类中创建一个复制构造函数:

    public Employee(Employee employee) {
        this.id = employee.id;
        this.age = employee.age;
        this.gender = employee.gender;
        this.firstName = employee.firstName;
        this.lastName = employee.lastName;
    }

使用Java 8流,您可以进行深拷贝:

List<Employee> listTwo = employeeList.stream().map(item -> new Employee(item)).collect(Collectors.toList());

11

它不会改变原始列表,但会改变同时包含在两个列表中的对象。

在这种情况下,使员工对象不可修改并提供创建更改属性与原始对象不同的副本对象的可能性可能非常有用。

如果您绝对不能修改Employee对象(甚至不能添加复制构造函数),则可以实现自己的复制/克隆方法(与被认为已损坏的Cloneable接口无关):

public static Employee clone_employee(Employee original) {
    return new Employee(original.getID(), original.getAge(), original.getGender(), original.getFirstName(), original.getLastName());
}

然后执行

employeeList.stream()
    .map(item -> clone_employee(item))
    .collect(Collectors.toList());

或者只是

employeeList.stream()
    .map(<thisclassname>::clone_employee)
    .collect(Collectors.toList());

基本上与Uata建议的相同,但需要您自己进行复制。


这只是一个例子,但我无法修改员工对象。解决方案是什么? - Makky
@Makky 看看Uata的回答,但我会扩展我的回答。 - glglgl
谢谢@glglgl,我会根据你的答案进行更改。 - Makky
避免使用Clone()方法和Cloneable接口 - 它们是有问题的 -> 这在《Effective Java》中已经被强调了。 - nanosoft
@nanosoft 感谢反馈。我修改了答案以考虑到这一点(如果没有复制构造函数,则不要使用clone(),而应该使用自己的方法)。 - glglgl
显示剩余3条评论

3

由于您无法更改Employee类本身,因此可以创建一个辅助方法来深度复制Employee实例(当然,您也可以直接调用构造函数,但我认为简单的方法更加清晰):

public static Employee copy(Employee original){
    return new Employe(original.id, original.age, original.gender, original.fname, original.lname);
}

接着您可以使用流(Stream)列表,并使用 map 操作来复制每个元素:

List<Employee> employeesCopy = employees.stream() // Stream<Employee>
    .map(e -> copy(e))                            // Stream<Employee>
    .collect(Collectors.toList());                // List<Employee>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接