关键字final

一、final变量

1.1常量

final关键字可用于声明变量,一旦该变量被设定,就不可以再改变该变量的值。此时变量又称作常量。例如,在类中定义PI值,可以使用如下语句:

final double PI=3.14;

规范:Java中定义全局常量,使用public static final修饰,这样的常量只能在定义是被赋值。

public static final double PI_VAULE = 3.14;

规范:被定义为final的常量定义时用大写字母命名,并且单词间用下划线进行连接。

代码演示:

import java.util.Random;

class Test {
    int i = 0;
}

/*
 * 常量示例
 * @author wsq
 */
public class FinalData {
    static Random rand = new Random();
    private final int VALUE_1 = 9; // 声明一个final常量
    private static final int VALUE_2 = 10; // 声明一个全局常量
    private final Test test = new Test(); // 声明一个final引用
    private Test test2 = new Test(); // 声明一个普通引用
    private final int[] a = {1, 2, 3, 4, 5, 6}; // 声明一个final数组
    private final int i4 = rand.nextInt(20);
    private static final int i5 = rand.nextInt(20);

    public String toString() {
        return "i4值:" + i4 + " i5值:" + i5 + " ";
    }

    public static void main(String[] args) {
        FinalData data = new FinalData();

        // 报错:不能改变定义为final的常量值
        // data.VALUE_1 = 8;

        // 报错:不能改变定义为final的常量值
        // data.VALUE_2 = 9;

        // 报错:不能将定义为final的引用指向其他引用
        // data.test = new Test();

        // 正确: 可以对指定为final的引用中的成员变量赋值
        data.test.i = 1;

        // 正确: 可以将没有定义为final的引用指向其他引用
        data.test2 = new Test();

        // 报错:不能对定义为final的数组赋值
        // int b[] = { 7, 8, 9 };
        // data.a = b;

        // 但是final的数组中的每一项内容是可以改变的
        for (int i = 0; i < data.a.length; i++) {
            data.a[i] = 9;
        }
        // 这个for循环可以替换为Arrays.fill(data.a, 9);

        System.out.println("旧创建的对象" + data);
        System.out.println("新创建的对象" + new FinalData());
    }
}

控制台输出:
在这里插入图片描述从上述执行结果中可以发现i5的值是相同的。

1.2全局常量

我们知道一个被定义为final的对象引用只能指向唯一一个对象,不可以将它再指向其它对象,但是一个对象的值却是可以改变的,那么为了使一个常量真正做到不可更改,可以将常量声明为static final。

示例:在项目中创建FinalStaticData类,在该类中创建Random类的对象,在主方法中分别输出类中定义的final变量a1与a2。

import java.util.Random;
import static java.lang.System.out;

/*
 * 全局常量
 * @author wsq
 */
public class FinalStaticData {
    private static final Random rand = new Random(); // 实例化一个Random类对象
    // 随机产生0~10之间的随机数赋予定义为final的a1
    private final int a1 = rand.nextInt(10);
    
    // 随机产生0~10之间的随机数赋予定义为static final的a2
    private static final int a2 = rand.nextInt(10);

    public static void main(String[] args) {
        FinalStaticData fdata = new FinalStaticData(); // 实例化一个对象
        // 调用定义为final的a1
        out.println("实例化对象调用a1的值:" + fdata.a1);
        // 调用定义为static final的a2
        out.println("实例化对象调用a2的值:" + fdata.a2);
        
        // 实例化另外一个对象
        FinalStaticData fdata2 = new FinalStaticData();
        out.println("重新实例化对象调用a1的值:" + fdata2.a1);
        out.println("重新实例化对象调用a2的值:" + fdata2.a2);
    }
}

控制台输出:
在这里插入图片描述

从运行结果中可以看出,定义为final的常量不是恒定不变的,将随机数赋予定义为final的常量,每次运行程序时会改变a1的值。但是a2与a1不同,由于它被声明为static final形式,所以在内存中为a2开辟了一个恒定不变的区域,当再次实例化一个FinalStaticData对象时,仍然指向a2这块内存区域a2是在装载时被初始化,而不是每次创建新对象时被初始化;而a1会重新实例化对象时被更改。

最后总结下在程序中final数据可以出现的位置,如下。

/*
 * 总结一下在程序中final数据可以出现的位置
 * @author wsq
 */
public class FinalArea
{
    // final成员变量不可更改
    final int VALUE_ONE = 6;

    // 在声明final成员变量时没有赋值,称为空白final
    final int BLANK_FINALVAULE;

    // 在构造方法中为空白final赋值
    public FinalArea()
    {
        BLANK_FINALVAULE = 8;
    }

    // 设置final参数,不可以改变参数x的值
    int doIt(final int x)
    {
        return x + 1;
    }

    // 局部变量定义为final,不可以改变i的值
    void doSomething()
    {
        final int i = 7;
    }
}

二、final方法

首先,被定义为final的方法不能被重写。
将方法定义为final类型可以防止子类修改该类的定义与实现方式,同时定义为final的方法执行效率要高。在修饰权限中有private修饰符,如果一个父类的某个方法被设置为private修饰符,子类将无法访问该方法,自然无法覆盖该方法,所以一个定义为private的方法隐式被指定为final类型。

语法:

private final void test(){
}

三、final类

定义为final的类不能被继承。
注意:如果将某个类设置为final形式,则类中的所有方法都被隐式设置为final形式,但是final类中的成员变量可以被定义为final或非final形式。

示例:在项目中创建FinalClass类,在类中定义doit()方法和变量a,实现在主方法中操作变量a自增。

/*
 * 定义final类
 * @author wsq
 */
final class FinalClass {
    int a = 3;

    void doit() {
    }

    public static void main(String args[]) {
        FinalClass f = new FinalClass();
        f.a++;
        System.out.println(f.a); // 结果:4
    }
}

4、总结

final关键字的好处:

  1. final关键字提高了性能。JVM和Java应用都会缓存final变量。
  2. final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
  3. 使用final关键字,JVM会对方法、变量及类进行优化。

不可变类:
创建不可变类要使用final关键字。不可变类是指它的对象一旦被创建了就不能被更改了。String是不可变类的代表。不可变类有很多好处,譬如它们的对象是只读的,可以在多线程环境下安全的共享,不用额外的同步开销等等。

final的重要知识点:
(1)final关键字可以用于成员变量、本地变量、方法以及类。
2)final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误。
(3)在匿名类中所有变量都必须是final变量。
(4)final方法不能被重写。
(5)final类不能被继承。
(6)final关键字不同于finally关键字,后者用于异常处理。
(7)final关键字容易与finalize()方法搞混,后者是在Object类中定义的方法,是在垃圾回收之前被JVM调用的方法。
(8)接口中声明的所有变量本身是final的。
(9)final和abstract这两个关键字是反相关的,final类就不可能是abstract的。
(10)final方法在编译阶段绑定,称为静态绑定(static binding)。
(11)没有在声明时初始化final变量的称为空白final变量(blank final variable),它们必须在构造器中初始化,或调用this()初始化。否则,编译器会报错“final变量(变量名)需要进行初始化”。
(12)将类、方法、变量声明为final能够提高性能,这样JVM就有机会进行估计,然后优化。
(13)按照Java代码惯例,final变量就是常量,而且通常常量名要大写。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王雀跃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值