返回可变对象的好方法

时间:2011-06-28 07:38:34

标签: java

假设我有一个类Comment,我有一个名为 commentDate 的私有字段,它是一个java.util.Date,并且有一个名为 getCommentDate 的getter。

为什么最好返回该日期的副本(返回新日期(commentDate.getTime()))而不是简单地返回该日期......

用户如何更改该日期的对象状态,因为它是一个getter而不是setter?

8 个答案:

答案 0 :(得分:13)

由于java.util.Date实施Cloneable,您可以轻松克隆日期,如下:

public class DateTest {
    private Date date;

    public DateTest() {

    }

    public Date getDate() {
        return (Date) date.clone();
    }

    public void setDate(Date date) {
        this.date = (Date) date.clone();
    }       
}

答案 1 :(得分:7)

首先,请,尽量避免使用getter和setter。如果你在同一个领域同时拥有它们,你几乎肯定会做错事。我不在乎Java专家告诉你什么。他们不知道他们在谈论什么。这不是OO的工作方式。 OO不是将字段访问转换为方法调用的make-work项目。这实际上并没有封装任何东西。

那说:如果你自己返回日期,那么调用代码会引用你的日期对象,并且可以使用它的完整界面。由于日期是可变对象,因此界面包含可以更改对象状态的内容。由于引用是您的日期,您的日期状态将会更改。调用代码如何得到日期并不重要(即“带有吸气剂”)。

答案 2 :(得分:5)

  

用户如何更改对象状态   那个日期,因为它是一个吸气剂,而不是   一个二传手?

轻松:

Comment comment = new Comment();
comment.getCommentDate().setTime(0); // now it's January 1, 1970 00:00:00 GMT.

答案 3 :(得分:2)

按照Tapas Bose的例子,我们可以使用JAVA 8来处理NULL情况:

public class DateTest {
private Date date;

public DateTest() {

}

public Date getDate() {
    return Optional.ofNullable(date).map(Date::getTime).map(Date::new).orElse(null);
}

public void setDate(Date inputDate) {
    this.date= Optional.ofNullable(inputDate).map(Date::getTime).map(Date::new).orElse(null);
}}

参考:Is there a way to copy Date object into another date Object without using a reference?(Nicolas Henneaux的答案)

答案 4 :(得分:1)

用户无法“替换”getCommentDate()提供的实例。但是,用户可以调用getCommentDate()。setMonth(10),从而修改日期。因此,如果这是一个问题,我建议你返回“原始”实例的副本。

答案 5 :(得分:1)

由于java.util.Date是可变的,因此可以通过getter更改它:

getCommentDate().setYear(2011)

这会导致评论中的commentDate更改为2011年。Date上的所有其他设置方法也可以调用,当然只是一个示例。

答案 6 :(得分:0)

在Java中,您正在处理引用。当你有一个getter并返回 commentDate 时,你实际上正在返回对该对象的引用。这意味着,由于getter返回的引用,调用者可以操作的私有字段中的相同对象。

答案 7 :(得分:0)

注意:不要通过getters返回可变对象。日期(在Java 8之前)。流氓程序员始终可以将其重置。假设您编写了一个程序,其中根据工作年限计算员工的社会保障福利。

public class Employee {
// instance fields
private String name;
private String nickName;
private double salary;
private Date hireDay;

// constructor
Employee(String name, String aNickName, double aSalary, int aYear,
        int aMonth, int aDay) {
    this.name = name;
    nickName = aNickName;
    salary = aSalary;
    GregorianCalendar cal = new GregorianCalendar(aYear, aMonth - 1, aDay);
    hireDay = cal.getTime();
}
//needs to be corrected or improved  because date is a mutable object
public Date getHireDay() {
    return hireDay;
}

黑客/不良程序员可以使用setter重置日期

Employee john = new Employee("John", "Grant", 50000, 1989, 10, 1);
    Date d = john.getHireDay();

    // Original hire date is Oct 1, 1989
    System.out.println("Original hire date "+ d.getTime()));

    long tenYearsInMilliseconds = 10 * 365 * 24 * 60 * 60 * 1000L;
    long time = d.getTime();

    // Hire date after hacker modifies the code
    d.setTime(time - tenYearsInMilliseconds);
    System.out.println("Hacked hire date "+john.getHireDay().getTime()));
}

相反,..返回Java 7的date方法的克隆或使用Java 8的LocalDate类。

 // for Java 7
public Date getHireDay() {
    return (Date)hireDay.clone();
}

//for Java 8
public LocalDate getHireDay() {
    return hireDay;
}