以下筆記摘自《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調用更改器方法可以自動的改變這個雇員對象的私有狀态。