面向对象特性——封装
封装的优点
最后再仔细看一下非常简单的getName、getSalary和getHireDay方法
public double getSalary()
{
return salary;
}
public LocalDate getHireDay()
{
return hireDay;
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
这些都是典型的访问器方法。由于它们只返回实例字段值,因此又称之为字段访问器。
如果将name、salary和hireDay字段标记为公共,而不是编写单独的访问器方法,难道不是更容易一些吗?
name只是一个只读字段,一旦在构造器中设置,就没有任何方法可以对它进行修改,这样我们就可以确保name字段不会受到外界的破坏。
虽然salary不是只读字段,但是它只能用raiseSalary方法修改。特别是一旦知道这个值出现了错误,只要调试这个方法就可以了。如果salary是公共的,破坏这个子段值的捣乱者就可能出现在任何地方(那就很难调试了)。
有些时候,可能想要或者或设置字段值,那么需要下面三项内容:
- 一个私有数据字段
- 一个公共的字段访问器方法
- 一个公共的字段修改器方法
这样做要比提供一个简单的公共数据字段复杂些,但却有着下列明显的好处:
首先,可以改变内部实现,而除了该类的方法以外,这不会影响其他代码。例如,如果将存储的字段修改为:
String firstName;
String lastName;
那么getName方法可以返回
firstName+" "+lastName
这个改变对于程序的其他部分是完全不可见的。
当然,为了进行新旧数据表示之间的转换,访问器方法和更改器方法可能需要做许多工作。但是,这将为我们带来第二点好处:更改器方法可以完成错误检查,而只对字段赋值的代码可能没有这个麻烦。比如,setSalary方法可以检查工资是否小于0.
注意不要返回可变对象引用的访问器方法,这样会破坏封装性。如果需要返回一个可变对象的引用,首先应该对它进行克隆,返回这个克隆的对象。
这里给出一个经验,如果需要返回一个可变数组字段的副本,就应该使用clone
私有方法
通过将方法设计为私有,如果你改变了方法的实现方式,就没有义务保证这个方法依然可用。如果数据的表示发生了变化,这个方法可能变得难以实现,或者不再需要;这并不是重点。重点在于,只要方法是私有的,类的设计者就可以确信它不会再别处使用,所以可以将其删去。如果一个方法是公共的,就不能简单地将其删除,因为可能会有其他代码依赖这个方法。
可见性
java的可见性public/protect/private,有两个层次——类级别和字段、方法级别
类级别:
类级别 | / | public |
---|---|---|
同一个包内 | ok | ok |
其他包 | ok |
字段、方法级别
字段、方法级别 | private | protect | / | public |
---|---|---|---|---|
同一个类 | ok | ok | ok | ok |
子类 | ok | ok | ok | |
同一个包的类 | ok | ok | ||
其他包的类 | ok |