最近在翻翻以前看过的书,看到Core Java里的一句话:As a rule of thumb, always use clone whenever you need to return a copy of a mutable data field. 大意是说:一般来讲,对于返回变化的变量,最好用clone()方法。结合上下文来理解这句话,其言外之意,就是如果不经处理的返回实例的对象变量或者属性,是一种破坏封装的行为。
还是先来看下最直接的破坏封装的编程行为:
class Person{ public int age; //public修饰变量,导致封装被破坏 public Person(int age){ this.age = age; } public String toString(){ return "The person's age is "+ age; } } public class NotGood { public static void main(String args[]){ Person p = new Person(24); p.age = 40; //能够直接通过变量访问变量,而不是通过方法 System.out.println(p); } }
上面的代码,明显的反应了封装的一个基本思想:通过类自身的方法去访问或者改变变量,而不应该直接通过类的实例化对象直接去操作变量。
回到我们开始是提起的那句话,那为什么不能直接返回可变的变量呢?看代码和输出:
import java.util.*; import java.text.*; class Person{ private int age; private Date birthday; public Person(int age, int year, int month, int day){ this.age = age; GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day); this.birthday = calendar.getTime(); } public int getAge(){ return age; } public Date getBirth(){ return birthday; } public String toString(){ return "The person's age is "+ age +", and born at "+ new SimpleDateFormat("yyyy-MM-dd").format(birthday) +"."; } } public class NotGood { public static void main(String args[]){ Person p = new Person(24, 1984, 12, 1); int i = p.getAge(); i++; System.out.println(p); Date d = p.getBirth(); double tenYearsInMilliSeconds = 10 * 365.25 * 24 * 60 * 60 * 1000; d.setTime(d.getTime() - (long) tenYearsInMilliSeconds); System.out.println(p); } }
结果:
The person's age is 24, and born at 1984-12-01. The person's age is 24, and born at 1974-12-01.
可以看出来,对于基本类型的变量输出没有影响,但是如果变量是个对象的话,修改之后,就会对原始的对象变量的内容。这就Core Java这句话的意思。按照它的建议,应该处理下,最直接的办法就是利用clone()方法。看代码和输出:
import java.util.*; import java.text.*; class Person{ private int age; private Date birthday; public Person(int age, int year, int month, int day){ this.age = age; GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day); this.birthday = calendar.getTime(); } public int getAge(){ return age; } public Date getBirth(){ return (Date)birthday.clone(); //在这里进行修改 } public String toString(){ return "The person's age is "+ age +", and born at "+ new SimpleDateFormat("yyyy-MM-dd").format(birthday) +"."; } } public class NotGood { public static void main(String args[]){ Person p = new Person(24, 1984, 12, 1); System.out.println(p); Date d = p.getBirth(); double tenYearsInMilliSeconds = 10 * 365.25 * 24 * 60 * 60 * 1000; d.setTime(d.getTime() - (long) tenYearsInMilliSeconds); System.out.println(p); } }
输出:
The person's age is 24, and born at 1984-12-01. The person's age is 24, and born at 1984-12-01.