4.3.5 隐式参数与显式参数
方法用于操作对象以及存取它们的实例域.例如,方法:public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
将调用这个方法的对象的salary实例域设置为新值.看看下面这个调用:
number007.raiseSalary(5);
它的结果将number007.salary域的值增加5%.具体地说,这个调用将执行下列指令:
double raise = number007.salary * 5 / 100;
number007.salary += raise;
raiseSalary方法有两个参数.第一个参数称为隐式(implicit)参数,是出现在方法名前的Employee类对象.第二个参数位于方法名后面括号中的数值,这是一个显式(explicit)参数.
可以看到,显式参数是明显地列在方法声明中的,例如 double byPercent .隐式参数没有出现在方法声明中.
在每一个方法中,关键字 this 表示隐式参数.如果需要的话,可以用下列方式编写raiseSalary方法:
public void raiseSalary(double byPercent)
{
double raise = this.salary * byPercent / 100;
this.salaray += raise;
}
有些程序员更偏爱这样的风格,因为这样可以将实例域与局部变量明显地区分开.注释:在C++中,通常在类的外面定义方法:
void Employee::raiseSalary(double byPercent); // C++ not Java
{
...
}
如果在类的内部定义方法,这个方法将自动地成为内联(inline)方法.
class Employee
{
...
int getName() { return name; } // inline in C++
}
在Java中,所有的方法都必须在类的内部定义,但并不表示它们是内联方法.是否将某个方法设置为内联方法是Java虚拟机的任务.
4.3.6 封装的优点
最后再看一下简单的getName方法public String getName()
{
return name;
}
它是典型的访问器方法,由于它只返回实例域值,因此又称为域访问器.
将name域标记为 public,依次来取代独立的访问器方法会不会更容易呢?
关键在于name是一个只读域.一旦在构造器中设置完毕,就没有任何一个方法可以对它进行修改,这样确保name域不会受到外界的破坏.
在有些时候,需要获得或设置实例域的值.因此, 应该提供下面三项内容:
一个私有的数据域
一个公有的域访问器方法
一个公有的与更改器方法
这样做要比提供一个简单的公有数据域复杂些,但却有着下列明显的好处:
首先,可以改变内部实现,除了该类的方法之外,不会影响其他代码.
例如,如果将存储名字的域改为:
String firstName;
String lastName;
那么getName方法可以改为返回
firstName + " " + lastName
对于这点改变,程序的其他部分完全不可见.
当然,为了尽心新旧数据表示之间的转换,访问器方法和更改器方法有可能需要做许多工作.但是,这将为我们带来 第二点好处:更改器方法可以执行错误检查,然而直接对域进行赋值将不会进行这些处理.例如,setSalary方法可以检查薪金是否小于 0 .
警告:注意不要编写返回引用可变对象的访问器方法.
4.3.7 基于类的访问权限
方法可以访问所调用对象的私有数据.一个方法可以访问所属类的所有对象的私有数据.下面看一下用于比较两个雇员的equals方法class Employee
{
...
public boolean equals(Employee other)
{
return name.equals(other.name);
}
}
典型的调用方式是
if (harry.equals(boss)) ...
这个方法访问harry的私有域,并且还访问了boss的私有域.这是合法的,其原因是boss是Employee类对象,而Employee类的方法可以访问Employee类的任何一个对象的私有域.
注释:C++也有同样的原则.方法可以访问所属类的私有特性,而不仅限于访问隐式参数的私有特性.
4.3.8 私有方法
对于私有方法,如果改用其他方法实现相应的操作,则不必保留原有的方法.如果数据的表达方式发生了变化,这个方法可能会变得难以实现,或者不再需要.然而,只要方法是私有的,类的设计者就可以确信:它不会被外部的其他类操作调用,可以将其删除.如果方法是公有的,就不能将其删除,因为其他的代码很可能依赖它.4.3.9 final 实例域
可以 将实例域定义为 final,构造对象时必须初始化这样的域,并且在后面的操作中,不能够再对它进行修改.例如,可以将Employee类中的name域声明为 final,因为在对象构建之后,这个值不会再被修改,即没有setName方法.class Employee
{
private final String name;
...
}
final 修饰符大多应用于基本类型域,或不可变类的域(如果类中的每个方法都不会改变其对象,这种类就是不可变的类,例如String类).