final关键字用在三种情况下,数据、方法和类。
1.final数据,如果是基本数据类型,那么表明,这个基本数据必须在定义的时候初始化或者使用前进行初始化。如果是对象引用的话,那么表明它不能再指向其他的其他的对象,但是引用的对象本身是可以改变的。
FinalData.java
import java.util.*;

class Value{
 int i;
 public Value(int i){this.i=i;}
}

public class FinalData{
 private static Random rand =new Random();
 private String id;
 public FinalData(String id){this.id=id;}
 
 private final int VAL_ONE=9;
 private static final int VAL_TWO=99;//final的基本常量采用全部字母大写,并且字与字时间用下划线的形式
 
 private final int i4=rand.nextInt(20);
 static final int i5= rand.nextInt(20);
 
 private Value v1=new Value(11);
 private final Value v2=new Value(22);
 private static final Value v3=new Value(33);
 
 public String toString(){
  return id+": "+"i4= "+i4+", i5="+i5+" VAL_ONE= "+VAL_ONE;
 }
 
 public static void main(String[] args){
  FinalData fd1=new FinalData("fd1");
  
  //fd1.VAL_ONE++;  //不能修改final的基本数据类型
  //fd1.v2=new Value(22);//不能修改引用对象
  fd1.v2.i++;
  
  FinalData fd2=new FinalData("fd2");
  
  System.out.println(fd1);
  System.out.println(fd2); 
 }
}

打印结果:
fd1: i4= 10, i5=12 VAL_ONE= 9
fd2: i4= 13, i5=12 VAL_ONE= 9

结果表明,编译时常量(在编译时就能确定的final数据)和static final对象是不会改变的。
Java还允许在参数列表中以声明的形式将参数指明为final的,如下
void with (final String s){
   ……
}
说明在with函数中你可以读s这个参数,但是不能改变它。

2.final函数
FinalMethod.java

class WithFinal{
 public final void f(){
  System.out.println("WithFinal.f()");
 }
}

public class FinalMethod extends WithFinal {
 public void f(){
  System.out.println("FinalMethod.f()");
 }
 
 public static void main(String[] args){
  
  FinalMethod fm=new FinalMethod();
  fm.f();
  
  WithFinal wf=new WithFinal();
  wf.f();
 } 
}

上面的代码是不能通过编译的,因为如果一个方法申明为final,那么继承类就不能将其覆盖。如果将继承类的f()函数删除,那么打印输入如下:
WithFinal.f()
WithFinal.f()
即final想要确保在继承中使方法行为保持不变,不会覆盖。如果将final除掉,那么输出为:
FinalMethod.f()
WithFinal.f()
即基类的方法被覆盖,但基类的对象调用f()还是调用基类本身的函数,而不是继承类的函数,这点要注意。

现在将final前面public改成private看看会发生什么情况:
wf.f()行报错,说引用了private函数(说明wf引用对象调用的是基类的函数,而不是子类的f()),我们将此行注释掉,结果通过了编译,运行结果如下:
FinalMethod.f()
这是为什么呢?不是继承类不能覆盖基类的方法吗?
答案:“覆盖”只有在某方法使在基类的接口的一部分时才会出现,也就是说基类中的private方法并不是基类的接口,只是一些隐藏在类中的程序代码而已。所以此时并没有“覆盖”f()方法,而是在子类中生成了一个新的方法而已。

3.final类
final类容易理解,当某个类定义为final时,则不能继承此类。