以下笔记摘自《java核心技术卷1》
以下给出了一个薪金管理系统的一部分代码
package Employee;
import java.time.LocalDate;
public class Employee {
private String name;
private double salary;
private LocalDate hireDay;
public Employee(String name, double salary, int year,int month,int day) {
this.name = name;
this.salary = salary;
this.hireDay = LocalDate.of(year,month,day);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public LocalDate getHireDay() {
return hireDay;
}
public void setHireDay(LocalDate hireDay) {
this.hireDay = hireDay;
}
public void raiseSalary(double byPercent) {
double raise=salary*byPercent/100;
salary+=raise;
}
}
package Employee;
public class EmployeeTest {
public static void main(String[] args) {
Employee[] staff = new Employee[3];
staff[0] = new Employee("Carl",75000,1987,12,15);
staff[1]=new Employee("Harry",50000,1989,10,1);
staff[2]=new Employee("Tony",40000,1990,3,15);
for(Employee e : staff)
e.raiseSalary(5);
for(Employee e : staff)
System.out.println("name="+e.getName()+",salary="+e.getSalary()+",hireDay="+e.getHireDay());
}
}
封装的优点
关键字private确保只有Employee类自身的方法能够访问这些实例域,而其它类的方法不能够读写这些域。
public String getName() { return name; }
是典型的访问器方法。
将name、salary和hireDay域标记为public,以此来取代独立的访问器方法会不会更容易些呢?
name是一个只读域。一旦在构造器中设置完毕,就没有任何一个办法可以对他进行修改,这样来确保name域不会受到外界的破坏。
虽然salary不是只读域,但是它只能用raiseSalary方法进行修改,一旦这个域值出现了错误,只要调试这个方法就可以了。如果salary域是public的,破坏这个域值的捣乱者有可能会出现在任何地方,
有些时候,需要获得或设置实例域的值,应提供以下三种内容:
- 一个私有的数据域
- 一个共有的域访问器方法
- 一个公有的域更改器方法
这样做要比提供一个简单的共有数据域复杂些,但是却有着下列明显的好处:
1、首先,可以改变内部实现,除了该类的方法之外,不会影响其他代码。
例如:如果将存储名字的域改为:
String firstName;
String lastName;
那么,getName方法可以改为返回
fisrtName+""+lastName
对于这点改变,程序的其他部分完全不可见。
2、为了进行新旧数据表示之间的转换,访问其方法和更改器方法有可能需要做许多工作。但是,浙江为我们带来了第二点好处:更改器方法可以执行错误检查,然而直接对域进行赋值将不会进行这些处理。例如setSalary方法可以检查新近是否小于0。
注意:不要编写“返回可变引用对象”的访问器方法!
现在假如把Employ类中的
private LocalDate hireDay;部分改为private Date hireDay;就会出问题。
LocalDate类没有更改器方法,与之不同,Date类有一个更改器方法setTime,可以在这里设置毫秒数。
Date对象是可变的,这一点就破坏了封装性。
假如有人写
Employee harry=...; Date d=harry.getHireDay(); double tenYearsInMilliSeconds=10*365.25*24*60*60*1000; d.setTime(d.getTime()-(long)tenYearsInMilliSeconds);
那么,d和harry.hireDay引用同一个对象,对d调用更改器方法可以自动的改变这个雇员对象的私有状态。