Blog
It's a Wonderful Life
java中如何避免类的私有域被篡改
来看下面一段代码:
public class test
{
public static void main(String[] args)
{
Employee leo = new Employee("leo", 1_000_000_000, 2017, 4, 15);
Date d = leo.getHireday();
d.setTime(d.getTime() - 1000 * 60 * 60 * 24);
System.out.printf("Someone changed my hiredate to %tF", d);
System.out.printf(" It should be %tF!", leo.getHireday());
}
}
class Employee
{
private final String name;
private final double salary;
private final Date hireday;
public Employee(String n, double s, int year, int month, int day)
{
this.name = n;
this.salary = s;
GregorianCalendar date = new GregorianCalendar(year, month - 1, day);
this.hireday = date.getTime();
}
public Date getHireday()
{
return this.hireday;
}
public String getName()
{
return this.name;
}
public double getSalary()
{
return this.salary;
}
}
它的输出类似于:
Someone changed my hiredate to 2017-04-14 It should be 2017-04-15!
出现这种问题的原因是Date
是一个可变对象,语句Date d = leo.getHireday();
拿到的Date对象实际上和类leo
中的私有域hireday
指向同一块内存区域,所以任何对d
的修改都会导致employee
类的私有域变化,进而破坏了类的封装性。
要修复这一问题也是很方便的,只要留意对返回可变对象的函数调用clone()
方法就可以了,以下是修改后的代码:
public class test
{
public static void main(String[] args)
{
Employee leo = new Employee("leo", 1_000_000_000, 2017, 4, 15);
Date d = leo.getHireday();
d.setTime(d.getTime() - 1000 * 60 * 60 * 24);
System.out.printf("You can change it to %tF", d);
System.out.printf(" But I still get hired at %tF", leo.getHireday());
}
}
class Employee
{
private final String name;
private final double salary;
private final Date hireday;
public Employee(String n, double s, int year, int month, int day)
{
this.name = n;
this.salary = s;
GregorianCalendar date = new GregorianCalendar(year, month - 1, day);
this.hireday = date.getTime();
}
public Date getHireday()
{
return (Date)this.hireday.clone();
}
public String getName()
{
return this.name;
}
public double getSalary()
{
return this.salary;
}
}
它的输出类似于:
You can change it to 2017-04-14 But I still get hired at 2017-04-15