Java不可编写返回引用可变对象的访问器方法

最近在看java核心技术,在之前写代码的过程中没有意识到 “不可编写返回引用可变对象的访问器方法” 这一知识点,特此记之。
转载自 https://blog.csdn.net/m0_37620545/article/details/77895518

问题:
使用java进行编程时,有时会发现在一个类中明明定义的是private类型,结果却能够在其他类中被修改。
代码:

class Employee
{
    private String name;
    private double salary;
    private Date hireDay;

    public Date getHireDay(){
        return hireDay;
    }

}
    Employee harry = new Employee("harry",75000,1987,12,15);
    Date d = harry.getHireDay();
    double tenYearsInMilliSeconds = 10 * 365.25 * 24 * 60 * 60 * 1000;
    d.setTime(d.getTime() - (long)tenYearsInMilliSeconds);
    System.out.println(harry.getHireDay());

按理说这里hireDay定义成了Date,此时打印输出的harry的雇佣日期应该是1987年,结果却是“Wed Dec 14 12:00:00 CST 1977”?!
出错的原因很微妙。d和harry.HireDay引用了同一个对象,对调用更改其方法就可以自动的改变这个雇员对象的私有状态。如果这里在main函数中更改引用的salary,就不会出现这个问题,如:

class Employee
{
    private String name;
    private double salary;
    private Date hireDay;

    public double getSalary(){
        return salary;
    }
}
    double test = harry.getSalary();
    test = 50;
    System.out.println(test);
    System.out.println(harry.getSalary());

打印结果:
50.0
75000.0
解决方法:
如果需要返回一个可变对象的引用,应该首先对它进行克隆。对象clone是指存放在另一个位置上的对象副本。下面是修改后的代码:

class Employee
{
    private String name;
    private double salary;
    private Date hireDay;

    public Date getHireDay(){
        return hireDay.clone();
    }
}

凭经验可知,如果需要返回一个可变数据域的拷贝,就应该使用clone。
这里有的同学可能会想到,如果hireDay用final修饰,是不是就解决了这个问题呢?然而事实并非如此,对于可变的类,使用final修饰符可能会对读者造成混乱。private final Date hireDay;仅仅意味着存储在hireDay变量中的对象引用在对象构造之后不能被改变,而并不意味着hireDay对象是一个常量。任何方法都可以对hireDay引用的对象调用setTime更改器。
参考:Java核心技术。

猜你喜欢

转载自blog.csdn.net/qq_37111953/article/details/81709278