1.访问控制符
把该隐藏的隐藏,把该暴露的暴露出来,这两个方面都需要通过访问控制符来实现,java中的访问修饰符包括public、protected、private和default(缺省),这些访问修饰符控制着类、成员变量以及成员方法的访问控制
下面表中描述了public、protected、private和default(缺省)这4中访问控制符的访问权限:
public | protected | default(缺省) | private | |
---|---|---|---|---|
本类 | 可见 | 可见 | 可见 | 可见 |
本类所在包 | 可见 | 可见 | 可见 | 不可见 |
其他包中的子类 | 可见 | 可见 | 不可见 | 不可见 |
其他包中的非子类 | 可见 | 不可见 | 不可见 | 不可见 |
注意:声明类时,如果不适用public修饰符设置类的权限,则这个类默认为default(缺省)修饰。
java语言中,类的权限设定会约束类成员的权限设定,例如,定义一个default(缺省)的Anyclass类,然后在该类中定义一个public的doString()方法,那么,不论doString()方法加不加public修饰符,他的访问权限都是default(缺省)
使用访问控制符,需要遵守以下原则:
- 大部分顶级类都使用public修饰符;
- 如果某个类主要用作其他类的父类,该类中包含的大部分方法只是希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰符;
- 类中的绝大部分属性都应该使用private修饰,除非一些static或者类似全局变量的属性,才考虑使用public修饰;
- 当定义的方法只是用于辅助实现该类的其他方法(即工具方法)时,应该使用private修饰;
- 希望允许其他类自由调用的方法应该使用public修饰;
2.final关键字
final的含义是最后的、最终的,换言之,被final修饰的类、方法和变量不能被改变。
2.1final类
被final修饰的类不能被继承,如果希望一个类不允许任何类继承,并且不允许其他人对这个类进行任何改动,可以将这个类设置为final类。final类的语法如下:
final class 类名{ }
当把某个类设置为final类时,类中的所有方法都被隐式的设置为final形式,但是final类中的成员变量既可以被定义为final形式,又可以被定义为非final形式。
2.2final方法
被final修饰的方法不能被重写,将方法定义为final类型可以防止子类修改该方法的定义与实现方式,同时final方法的执行效率要高于非final方法,在修饰权限中曾经提到过private修饰符,如果一个父类的某个方法被设置为private修饰符,子类将无法访问该方法,自然无法覆盖该方法,所以一个定义为private的方法隐式被指定为final类型,这样无须将一个定义为private的方法在再定义为final类型,例如下面的语句。
public final void test() {
//省略一些程序代码
}
下面看一个实例,创建一个FinalMethod类,在该类中创建Parents类和继承该类的Sub类,在主方法中分别调用这两个类中的方法,并查看final类型方法能否被覆盖,代码如下:
class Parents {
private final void doit() {
System.out.println("父类.doit()");
}
final void doit2() {
System.out.println("父类.doit2()");
}
public void doit3() {
System.out.println("父类.doit3()");
}
}
class Sub extends Parents {
public final void doit() { // 在子类中定义一个doit()方法
System.out.println("子类.doit()");
}
// final void doit2(){ //final方法不能覆盖
// System.out.println("子类.doit2()");
// }
public void doit3() {
System.out.println("子类.doit3()");
}
}
public class FinalMethod {
public static void main(String[] args) {
Sub s = new Sub(); // 实例化
s.doit(); // 调用doit()方法
Parents p = s; // 执行向上转型操作
// p.doit(); //不能调用private方法
p.doit2();
p.doit3();
}
}
返回结果:
子类.doit()
父类.doit2()
子类.doit3()
从上面实例看出,final方法不能被覆盖,例如,doit2()方法不能再子类中被重写,但是在父类中定义了一个private final的doit()方法,同时在子类总定义了一个doit()方法,从表面上看,子类中的doit()方法覆盖了父类的doit()方法,但是覆盖必须满足一个对象向上转型为它的基本类型并调用相同方法这样的一个条件,又如,在主方法上使用Parents p=s语句执行向上转型操作,对象p只能调用正常覆盖doit3()方法,却不能调用doit()方法,可见子类中的doit()方法并不是正常覆盖,而是生成了一个新的方法。
2.3final变量
final关键字可用于修饰变量,一旦变量被final修饰,就不可以再改变变量的值,通常,把被final修饰的变量称作位常量,例如,在类中定义值为3.14的PI常量,可以使用如下语句:
final double PI = 3.14;
如果在程序中再次对PI常量赋值,编译器将会报错。
final修饰变量时,必须在声明时对其进行赋值操作,final除了可以修饰基本数据类型的常量,还可以修饰对象引用,例如被final修饰的数组,一旦一个对象引用被final修饰后,它只能恒定指定一个对象,无法指向另一个对象,一个即是static有事final的字段占据了一段不能改变的存储空间。