目录
在Java中,final通常是指“这是无法改变的”,使用final的原因可能是因为:设计和效率。从可能使用到final关键字的三种情况来了解它:数据、方法和类。
final数据
在Java中,编译期常量这类数据必须是基本数据类型,并且以关键字final表示,该类常量在定义时必须对其进行赋值。
一个既是static又是final的域只占据一段不能改变的存储空间。
对于基本数据类型,final使数值恒定不变;而对于对象的引用,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象,然而该对象自身却是可以改变的。
通过下列代码来理解final和static final:
import java.util.Random;
public class FinalData {
private static Random rand = new Random(47);
private String id;
public FinalData(String id) {
this.id = id;
}
private final int i = rand.nextInt(20);
private static final int Value = rand.nextInt(20);
@Override
public String toString() {
return id + ": " +
"i= " + i +
" Value: " + Value;
}
public static void main(String[] args) {
FinalData fd1 = new FinalData("fd1");
System.out.println(fd1);
//fd1.i = 5;Error: 当数据定义为final时,不能再对其进行改变
System.out.println("创建一个新的FinalData对象");
FinalData fd2 = new FinalData("fd2");
System.out.println(fd2);
}
}
运行结果如下:
在上述代码中,i是用final定义的,Value是用static final定义的,为了更加清晰地理解它们的含义,在初始化时利用了随机生成的方法。通过运行结果,可以看出:
①final使数据成为一个常量,在该对象的引用中不能对其进行改变,但是在创建一个新的对象的值,i会发生改变,说明final只能使定义的变量在该对象的引用中是唯一性的;
②Value不论是在该对象的引用或者是在创建新对象时,都不会发生改变,因为它是static定义的,在装载时已被初始化,而不是在创建新对象时初始化。
final参数
Java允许在参数列表中以声明的方式将参数指明为final。这意味着无法在方法中更改参数引用所指向的对象。
例如:
public int g(final int i){
return i + 1;
}
final方法
使用final方法的原因有两个:①把方法锁定,以防止任何继承类修改它的含义;②为了提高效率。
final和private关键字
类中所有的private方法都是隐式地指定为是final的,由于无法用private方法,所以也就无法覆盖它(修改它的含义)。可以对private方式使用final修饰,但这不会给该方法增加任何的额外含义。
通过下列代码来理解final方法:
class WithFinal{
private final void f(){
System.out.println("WithFinal.f()");
}
private void g(){
System.out.println("WithFinal.g()");
}
}
class FinalInit extends WithFinal {
private final void f(){
System.out.println("FinalInit.f()");
}
private void g(){
System.out.println("FinalInit.g()");
}
}
class FinalInit1 extends FinalInit{
public final void f(){
System.out.println("FinalInit.f()");
}
public void g(){
System.out.println("FinalInit.g()");
}
}
public class Final extends FinalInit{
public static void main(String[] args) {
FinalInit1 op1 = new FinalInit1();
op1.f();
op1.g();
//可以发生向上转型
FinalInit op = op1;
//但不能调用FinalInit的方法
//op.g(); Error: FinalInit中的方法是以private修饰的
//op.f(); Error: FinalInit中的方法是以private修饰的
WithFinal wp = new WithFinal();
//wp.g(); Error: WithFinal中的方法是以private修饰的
//wp.f(); Error: WithFinal中的方法是以private修饰的
}
}
通过上述代码可以看出,当方法以private定义时,它就不是基类的接口的一部分,它仅是一些隐藏于类中的代码,只不过具有相同的名称。但如果在导出类中以相同的名称生成一个public、protected或包访问权限的方法,该方法就不会产生在基类中出现的“仅具有相同名称”的情况。此时并没有覆盖该方法,只是生成了一个具有相同名字的新方法。
由于private方法无法触及而且能够有效隐藏,所以我们不需要过多的考虑它,只把它看做是因为它所归属的类的组织结构的原因而存在。
final类
当某个类的整体定义为final时,就表明了该类永远无法被继承。
定义方式:
final class Test{
int i = 7;
int j = 1;
}
在写代码的过程中,可以根据自己的意愿来选择是否要将该类定义为final类。由于final类禁止继承,所以final类中的所有方法都隐式的定义为final的,因为无法覆盖它们。在final类中可以给方法添加final修饰词,但这没有任何意义。