为什么在 Java 中修改创建的对象是错误的?

Why a modification of the created object is bad in Java?

我们都知道Java中的对象是可以修改的

我想在处理一个对象时提出三个选项并指出它们的优点和缺点。

public class SetterApplication {
    public static void main(String[] args) {
        User john = new User("John", 22);
        increaseAge(john, 2);
        System.out.println(john);       // User{name='John', age=24}

        User johnUpper = upperName(john);
        System.out.println(johnUpper);  // User{name='JOHN', age=24}
        System.out.println(john);       // User{name='JOHN', age=24}

        User johnLower = lowerName(john);
        System.out.println(johnLower);   // User{name='john', age=24}
        System.out.println(johnUpper);   // User{name='JOHN', age=24}
    }

    /**
     * Case #1
     * change the object passed in and return nothing
     * @param user user
     * @param inc inc
     */
    public static void increaseAge(User user, Integer inc) {
        user.setAge(user.getAge() + inc);
    }

    /**
     * Case #2
     * change the passed object and return the changed object
     * @param user user
     * @return User
     */
    public static User upperName(User user) {
        user.setName(user.getName().toUpperCase());
        return user;
    }

    /**
     * Case #3
     * do not change the passed object and return a completely new object
     * @param user user
     * @return User
     */
    public static User lowerName(final User user) {
        return new User(user.getName().toLowerCase(), user.getAge());
    }
}

class User {
    private String name;
    private Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("User{");
        sb.append("name='").append(name).append('\'');
        sb.append(", age=").append(age);
        sb.append('}');
        return sb.toString();
    }
}

"Case #1" - 最常见的方式,但要包含相应的缺点,即修改现有对象。但这种行为是可以预见的,因为我们没有 return 任何东西。

"Case #2" - 也经常出现在代码中。但这种情况具有误导性 - 因为它 return 是一个修改后的传输对象,这可能会误导我们正在 return 一个新对象,但事实并非如此。

"Case #3" - 这种方法是最时髦的方法。这里我们不修改传输对象和return一个新对象。但是这种方法有一个很大的缺点,在Java中不容易实现(深度)克隆,其次是它可能非常耗费资源,对象可能非常大。

我的问题是三个选项中哪个更可取?你喜欢用什么?您认为哪个选项最差?

这是一个广泛的话题。无论如何,不​​变性总是更受欢迎。
由于编写不可变 classes 通常很乏味(您可能想提供一个复制构造函数或复制方法。如果我只想复制其属性的某个子集怎么办?)我使用 Immutables图书馆。

只是不要让 class 实现 Cloneable 因为你想使用 clone 方法。
避免那个。您还需要一个显式转换。