final关键词主要可以用来变量的声明、final方法以及final类,下面逐个介绍。
final变量
final定义的变量,一旦被设定,就不可以再改变变量的值,同时必须在申明的时对其进行赋值操作(有些情况申明后赋值也可以,但是为培养良好的编程习惯,声明的时候赋值最好)。
final可以修饰一般的常量,同时也可以修饰对象引用,由于数组也可以被看作对象来引用,所以final也可以修饰数组。下面通过代码来直观解释:
class Yun{
final double PI;
public Yun(){
//这个函数会被报错,原因是没有给PI进行初始化
}
public Yun(double pi){
this.PI=pi;
}
/*public void setPi(double pi){
this.PI=pi; //这个函数是不被允许的,因为不能对final进行二次修改
}*/
public double GetPi(){
return PI;
}
}
public class Demo {
public static void main(String[] args) {
Yun y=new Yun(1); //调用含参构造函数,进行初始化
final double pi; //final定义的变量,申明时并未对其进行初始化
pi=3.14;
System.out.println("这是我定义的变量pi:"+pi);
System.out.println("这是Yun类中的pi:"+y.GetPi());
}
}
输出结果:
这是我定义的变量pi:3.14
这是Yun类中的pi:1.0
这个地方我们可以看到,在final修饰一个局部变量时,即使未在申明时对final修饰的变量进行初始化,随后初始化也是可以的,但这个是不好的编程习惯,这里只是给大家介绍一下。
在final修饰一个类的属性时,如果未在申明时或者构造函数中对其初始化,程序是绝对会报错的,上面的程序有报错,但是由于有含参构造函数存在,所以还是可以对其进行初始化,程序也还是可以运行并得出结果,但是建议大家还是养成良好的编程习惯。
import static java.lang.System.out;
import java.util.Random;
class T{
int i=0;
}
public class Demo {
static Random rand=new Random();
final int VALUE_1=9;
static final int num1=rand.nextInt(10);
final int num2=rand.nextInt(10);
final T test=new T();
final int[]a={1,2,3};
public static void main(String[] args) {
Demo demo=new Demo();
//demo.test=new Test(); //报错,final修饰的对象引用不能重新赋值
/*for (int i = 0; i < demo.a.length; i++) {
a[i]=9; //报错,final修饰的数组不能重新赋值
}*/
System.out.println(demo.VALUE_1);
System.out.println("num1="+demo.num1);
System.out.println("num2="+demo.num2);
Demo newDemo=new Demo();
System.out.println("newDemo num1="+newDemo.num1);
System.out.println("newDemo num2="+newDemo.num2);
}
}
输出结果:
9
num1=2
num2=3
newDemo num1=2
newDemo num2=9
上述代码中,对final修饰的对象引用test和数组a进行重新赋值都会报错,标明fianl修饰后的不可再更改性。
但是对于final修饰类的属性时,每定义一个对象,如上面代码所示,demo和newDemo的num2是不同的,不能够做到真正的不在改变,这个时候通过static final进行修饰,就可以完全的将值固定。public static final也进场用来修饰全局常量。
另外要说的是final修饰一个常量时,常量名要大写,名字是多个单词时用下划线分开,这样便于区分常量和变量(全大写的就是常量,一目了然,便于别人阅读),这个也是Java的编程规则。
final方法
特征:final方法不能被重写。
作用:当父类要定义一个不能被子类修改的方法是,可以用fianl进行修饰。这里提一下:父类的private方法,子类是无法访问的,所以private方法默认的都是有final修饰的,只不过省略了final关键字。
举个例子:
import static java.lang.System.out;
import java.util.Random;
class Parents{
private void doit(){
System.out.println("父类.doit()");
}
public void doit2(){
System.out.println("父类.doit2()");
}
final void doit3(){
System.out.println("父类.doit3()");
}
}
class Sub extends Parents{
private void doit(){
System.out.println("父类.doit()");
}
public void doit2(){
System.out.println("父类.doit2()");
}
/*final void doit3(){
System.out.println("父类.doit3()");
}*/
}
public class Demo {
public static void main(String[] args) {
Sub s=new Sub();
s.doit2();
s.doit3();
Parents p=s;
p.doit2();
//p.doit(); //无法调用
}
}
这里子类中的doit3()方法会报如下错误:
- Cannot override the final method from Parents
即说明子类不能覆盖一个final修饰的方法。
同时,在子类中对父类的doit()方法进行了重写,虽然没报错,在向上转型实际调用的时候是会报错的,所以p.doit()方法不可行,由于方法覆盖必须满足一个对象向上转型为它的基本类型并能正常调用相同方法,所以这里不能算覆盖成功,也就满足final修饰的方法不能被覆盖的说法。
final类
特征:final定义的类不能被继承
作用:用于修饰某个不允许被继承和修改的类
final类中的所有方法被隐式设置final形式,但是final类中的成员变量可以被定为非final或者final形式,也简单举个例子:
final class Demo {
int a=3;
void doit(){
}
public static void main(String[] args) {
Demo demo = new Demo();
demo.a++;
System.out.println(demo.a);
}
}
输出结果为
4