访问权限控制
修饰符 | 范围 |
---|---|
public | 范围最大,共有的,不管是谁都可以用 |
protectd | 范围次之,受保护的,只能是我的子孙后代可以用 |
包权限 | 范围在次之,只能在同一个包内,才可以用 |
private | 范围最小,我的就是我的,谁都不给 |
一些使用Tips:
- 子类可以放大父类的访问权限。列如,父类的方法是protected修饰的,在子类可以把修饰符改成public。就是说,儿子从老子那里接过来的传家宝,儿子觉得这什么都不是,当什么传家宝,就公开给狐朋好友调用了。但是子类不能缩小父类的访问权限。列如:父类的方法是public修饰的,子类不能改成protected。就是说,老子已经公开了,儿子不能去抢回来当传家宝了。
- 除内部类,类的修饰符只能有public和包权限。接口申明的方法只能是public的,抽象类的抽象方法不能是private
final关键字
根据语义表达的就是“这是无法改变的”。不想改变就两个理由:设计、效率。分下面三种情况:数据,方法,和类
final数据,用来告诉编译器一块数据是恒定不变的。主要两个作用:
- 一个永不改变的编译时常量
- 一个在运行是被初始化的值,不希望程序把它改变
对于编译期常量,编译器在编译的时候,可以将该常量值带入任何可能用到它的计算式中。当final修饰的对象引用的时候,则表示对此对应引用保持恒定不变。但是这个对象本身是可以变动的。一个被final和static同时修饰的变量则表示这是一块固有的、不能改变的。
final 方法
- 锁定方法,不让子类重写
- 效率问题,但是在Java SE5版本之后已经将这部分工作转到编译器和JVM优化中。
类中所有的private方法都隐式的指定为final的。所以private方法不存在是不是final类型的方法的问题
- final类
final修饰类的时候则表示这个类不可以被继承。
类初始化顺序
我们来通过一个例子进行理解
/**
* 注释里面的四位数字代表这个语句执行的位置
*/
class Child {
private int i = 9;
protected int j;
//4444
private int m = printInit("Child m initialized");
Child() {
//5555
System.out.println("i = " + i + ", j = " + j + ", m= " + m);
j = 39;
}
//1111
private static int x1 = printInit("static Child.x1 initialized");
public static int printInit(String msg) {
System.out.println(msg);
return 47;
}
}
class Parent extends Child {
//6666
private int k = printInit("Parent k initialized");
public Parent() {
//7777
System.out.println("k = " + k);
System.out.println("j = " + j);
}
//2222
private static int x2 = printInit("static Parent.x2 initialized");
public static void main(String[] args) {
//3333
System.out.println("Parent constructor");
Parent classOrder = new Parent();
}
}
我在上面的代码标注了输出的顺序,是不是有点蒙。我们一步一步来。
1. 程序需要执行,需要加载类,所以我们需要加载Parent和Child的类。加载class的时候就会把static对象加载。然后Parent继承与Child,所以Child会先一步加载,Parent会后一步加载。当然我们也可以知道如果Child还继承与别的Class的话,别的Class肯定是先于Child类加载的。所以到现在输出了上面1111,和2222语句对应内容
2. 调用Parent的构造函数,这个没得说。3333得以输出
3. 在实例化对象的时候,会调用构造函数这没得说。那为什么不是先输出6666对应的语句,反而是4444对应的语句呢。是因为子类在构造函数的第一句执行的是调用的父类的构造函数,所以Child的构造函数会被先调用。然后4444是在成员变量块,5555是在构造函数中。所以4444,5555输出出来了。然后才轮到Parent他自己初始化。所以6666,7777语句得以输出