在JAVA开发中,为类中的成员变量添加get和set方法是大家习以为常的事情了。但凡有可能会在其他类中使用或修改该类的成员变量,get方法与set方法肯定是第一选择。特别是在web开发中与数据库字段相对应的实体类,get方法与set方法更是比不可少的。那么有人想过get方法有可能会破坏类的封装么?
最近在翻看Core JAVA这本经典的JAVA书来巩固一下基础知识,突然看到了get方法可能会破坏类的封装,对此我表示十分的困惑。于是仔细研读,并经过编码试验发现确实如此。
我先定义了两个实体类People、Employee和一个包含main函数的可执行类
public class People{
private String name;
private Integer sex;
private Date birthday;
public People(String n, Integer s, Date b){
name = n;
sex = s;
birthday = b;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
public class Employee{
private People people;
private double salary;
public Employee(People p, double s){
people = p;
salary = s;
}
public People getPeople(){
return people;
}
public void setPeople(People p){
people = p;
}
public double getSalary(){
return salary;
}
public void setSalary(double s){
salary = s;
}
}
public class Main {
public static void main(String[] args) {
Employee e = new Employee(new People("hello", 0, new Date()), 2000d);
People p = e.getPeople();
String name = p.getName();
Integer sex = p.getSex();
Date birthday = p.getBirthday();
System.out.println("------------------初始值-----------------------");
<pre name="code" class="java"><span style="white-space:pre"> </span>System.out.println(e.getPeople().getName());
System.out.println(e.getPeople().getSex());
System.out.println(e.getPeople().getBirthday().getTime());
name = "kitty";sex = 1;birthday.setTime(birthday.getTime() + 10000000);System.out.println("------------------第一次操作后-----------------------");
<span style="white-space:pre"> </span>System.out.println(e.getPeople().getName());
System.out.println(e.getPeople().getSex());
System.out.println(e.getPeople().getBirthday().getTime());
p.setName(name);p.setSex(sex);p.setBirthday(birthday);System.out.println("------------------第二次操作后-----------------------");System.out.println(e.getPeople().getName());System.out.println(e.getPeople().getSex());System.out.println(e.getPeople().getBirthday().getTime());}}
执行main函数,控制台输出的内容
------------------初始值-----------------------
hello
0
Wed May 20 15:23:39 CST 2015
------------------第一次操作后-----------------------
hello
0
Wed May 20 18:10:19 CST 2015
------------------第二次操作后-----------------------
kitty
1
Wed May 20 18:10:19 CST 2015
首先创建一个Employee实例,取出其中的成员变量people的值赋值给变量p,再取出p中的三个成员变量值分别赋值给了三个变量name,sex,birthday。
第一步打印出e中people中的成员变量值,分别为hello,0,Wed May 20 15:23:39 CST 2015。之后我对name,sex,birthday三个变量值进行了修改,再次打印e中people中的成员变量值,分别为hello,0,Wed May 20 18:10:19 CST 2015。结果e中的people中的name,sex的值并没有因为我的操作而出现改变,而birthday的值被改变了。之后我又把修改后的三个变量值赋值给了p,再一次打印e中people中的成员变量值,为kitty,1,Wed May 20 18:10:19 CST 2015,这次所有的值都与第一次的打印结果不同了而我却没执行过e的任何set方法。
究其原因,在调用一个类的get方法时,如果get方法的返回值类型不是基本数据类型或其包装类,并不会创建一个新的实例而是返回该get方法对应的变量的内存引用,之后如果对这个引用做了任何修改都会对类本身造成影响,从而破坏了类的封装。
建议:如果get方法的返回值类型不是基本数据类型或其包装类,应先对成员变量进行克隆,再将克隆出的副本返回。(有关克隆的知识不在本文讨论范围)
如有错误之处还请指正,转载请注明出处。