final的使用
修饰类
当整个类定义为final时,代表不打算继承这个类,即这个类是不能拥有子类的
final修饰的类中,所有方法都隐式为final,无法覆盖他们,所以给他们添加final关键字是没有意义的。
如果想要扩展final修饰的类该怎样去做呢?
继承是不可以了,可以通过组合的方式!比如我们想扩展String类
class MyString{
private String innerString;
// ...init & other methods
// 支持老的方法
public int length(){
return innerString.length(); // 通过innerString调用老的方法
}
// 添加新方法
public String toMyString(){
//...
}
}
修饰方法
- private方法是隐式的final
- 可以重载final方法
父类的final方法(private方法)是不可以被重写的,但可以被重载
如下是正确的:
public class FinalExampleParent {
public final void test() {
}
public final void test(String str) {
}
}
修饰参数
Java允许在参数列表中以声明的方式将参数指明为final,这意味这你无法在方法中更改参数引用所指向的对象。这个特性主要用来向匿名内部类传递数据。
修饰变量
思考一些问题:
所有final修饰的字段,都是编译器常量吗?
不是
public class Test {
//编译期常量
final int i = 1;
final static int J = 1;
final int[] a = {1,2,3,4};
//非编译期常量
Random r = new Random();
final int k = r.nextInt();
public static void main(String[] args) {
}
}
k的值由随机数对象决定,所以不是所有的final修饰的字段都是编译期常量,只是k的值在被初始化后无法被更改。
static final
static final修饰的字段必须在定义时赋值,否则编译器无法通过
static final所修饰的字段仅占据内存的一个一份空间,一旦被初始化之后便不会被更改。
blank final
Java允许生成空白final,也就是说被声明为final但又没有给出定值的字段,但是必须在该字段被使用之前被赋值,这给予我们两种选择:
- 在定义处进行赋值(这不叫空白final)
- 在构造器中进行赋值,保证了该值在被使用前赋值。
构造器方法增强了final的灵活性
public class Test {
final int i1 = 1;
final int i2;//空白final
public Test() {
i2 = 1;
}
public Test(int x) {
this.i2 = x;
}
}
可以看到i2的赋值更为灵活。但是请注意,如果字段由static和final修饰,仅能在声明时赋值或声明后在静态代码块中赋值,因为该字段不属于对象,属于这个类。
使用final的限制条件和局限性
当声明一个final成员时,必须在构造函数退出前设置他的值。
public class MyClass {
private final int myField = 1;
public MyClass() {
...
}
}
或者
public class MyClass {
private final int myField;
public MyClass() {
...
myField = 1;
...
}
}