Java学习笔记之深入理解关键字final

基本概念

final是Java中是一个保留的关键字,可以声明变量(包括成员变量[实例变量和静态变量]和局部变量)、方法和类。它通常指“这是无法改变的”。将变量、方法和类声明为final,JVM能够对其进行优化,进而提升性能。
其关键知识点如下:

  • final方法是在编译器绑定的,即静态绑定(可参考Java学习笔记之深入理解动态绑定和静态绑定)
  • final**成员变量**必须在声明的时候初始化或者在构造器中初始化
  • final**局部变量**必须在使用前进行初始化赋值
  • 当final变量是基本数据类型时,其数值恒定不变,且不能被更改;当final变量是引用类型时,其引用恒定不变,即不能再指向其它对象,但其引用指向的对象本身却是可以被修改的
  • final方法不能被重写
  • final类不能被继承
  • 类中所有的private方法都隐式地指定为final

final变量

无论是成员变量(包括实例变量和静态变量)还是局部变量,只要声明为final,就必须在使用前进行初始化,否则在编译期时出现错误。值得注意的是,成员变量如果没有声明为final,那么在使用前是可以不用进行初始化的,因为它们有默认值。(可参考Java学习笔记之变量类型)
例1:

import java.util.ArrayList;

public class FinalVarDemo {
    int var;                // It's OK!默认值为0
    //final int var_final;  // It's not OK! 必须在声明的时候初始化或者在构造器中初始化     
    final int var_instance  = 0;
    final ArrayList<String> arrayList = new ArrayList<>();

    void test(){
        //final int var_local;                   // It's not OK!局部变量在使用前必须进行初始化赋值
        final int var_local = 1; 
        //var_local = 2;                         // It's not OK!final局部变量值不能更改
        //var_instance = 1;                 // It's not OK!final实例变量值不能被更改
        //arrayList = new ArrayList<>(); // It's not OK!不能将final引用类型变量指向新的对象
        arrayList.add("hello");          // It's OK!可以改变对象本身
        arrayList.add("world");

        System.out.println("var = "+var);
        System.out.println("var_instance = "+var_instance);
        System.out.println("var_local = "+var_local);
        System.out.println("arrayList = "+arrayList);
    }

    public static void main(String[] srgs){
        FinalVarDemo finalVarDemo = new FinalVarDemo();
        finalVarDemo.test();        
    }
}

输出结果:

var = 0
var_instance = 0
var_local = 1
arrayList = [hello, world]

final参数

Java允许在参数列表中以声明的方法将参数指明为final。
例2:

class Dog{
    void bark(){}
}
public class FinalArg {
    void withFinal(final Dog dog){
        //dog = new Dog(); // Illegal! --dog is final
    }

    void withoutFinal(Dog dog){
        dog = new Dog(); // OK! --dog is not final
    }

    int f(final int i){
        //i++; // Illegal! --i is final,can't change
        return i + 1;
    }

    int g(int i){
        i++;   // OK! --i is not final
        return i;
    }
}

分析:将方法中的参数指定为final,意味着无法在方法中更改参数引用所指向的对象,如果是基本数据类型参数,不能改变其值,只能读取。这一特性,一般用来向匿名内部类传递数据。

final方法

方法前面加上final关键字,代表这个方法不可以被子类的方法重写。final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。
例3:

class Animal{
    private final void f(){
        System.out.println("Animal.f()");
    }
    private void g(){
        System.out.println("Animal.g()");
    }
}

class Dog extends Animal{
    public final void f(){
        System.out.println("Dog.f()");
    }
    public void g(){
        System.out.println("Dog.g()");
    } 
}

class Teddy extends Dog{
// It's not OK!final方法不能被覆盖
//  public final void f(){
//      System.out.println("Teddy.f()");
//  }
    public void g(){
        System.out.println("Teddy.g()");
    } 
}

public class FinalMethodDemo {
    public static void main(String[] args){
        Teddy teddy = new Teddy();
        teddy.f();
        teddy.g();
        Dog teddy1 = new Teddy();
        teddy1.f();
        teddy1.g();
        Animal teddy2 = new Teddy();
//      teddy2.f(); // It's not OK!final方法不能被覆盖
//      teddy2.g();
    }
}

输出结果:

Dog.f()
Teddy.g()
Dog.f()
Teddy.g()

结果分析:需要指明的是类中所有的private方法都隐式的指定为final。而final方法是不能被覆盖的。但从例3中的代码可以看出,覆盖一个private方法(隐含是final的)似乎是奏效的。类Dog继承于类Animal,并且覆盖了两个private方法,而且编译也没有出错。那么问题来了,谁说final方法是不能被覆盖的?一般来讲,重写方法使用的是动态绑定,如果类Dog真的是重写了类Animal中的两个private方法,那么输出应该是Animal.f()而不是Dog.f(),所以可以肯定的是,类Dog中的这两个方法并不是继承自类Animal,它只不过是具有相同的名称,仅此而已!当然,这说的是private方法,对于public final方法,如果你想要覆盖该方法,编译会出现错误提示,该方法不能被覆盖,正如例3中的代码写的一样。

final类

当将某个类定义为final时,表示该类不能被继承。final类通常功能是完整的。Java中有许多这样的类,如String,Interger以及其他包装类。

final class Animal{

}

//compilation error: cannot inherit from final class
class Dog extends Animal{ 

}

final, finally, finalize的区别

  • final 用于声明属性,方法和类, 分别表示属性不可变, 方法不可覆盖, 类不可继承
  • finally 是异常处理语句结构的一部分,表示总是执行
  • finalize 是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等. JVM不保证此方法总被调用

参考资料

  1. Java编程思想
  2. 深入理解Java中的final关键字
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值