Java final关键字详解

final关键字的作用

  • 修饰变量:被它修饰的变量不可改变,一旦赋了初始值,就不能被重新赋值

    被final修饰的常量名称,所有字母要大写

  • 修饰方法:该方法不可被子类重写,但是可以被重载

  • 修饰类:修饰的类不能被继承,比如:Math、String等类

修饰变量

final修饰变量相比修饰方法、修饰类,是使用最多的情况。

  • final修饰基本数据类型的变量:变量一旦初始化之后其数值就不能变更

  • final修饰对象引用类型的变量:变量一旦初始化之后就不能让其再指向其他的对象

代码示例如下
这里写图片描述
这里写图片描述

可以看出,变量name和person都不能重新赋值了

修饰方法

下面这段话摘自《Java编程思想》第四版第143页:

“使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。“

因此,如果只想明确禁止该方法在子类中被覆盖的情况下才将方法设置为final的。

注:类的private方法会隐式地被指定为final方法。

修饰类

前面有提到过,final修饰类时,该类就不能被继承。

代码示例如下
这里写图片描述

如果某个类你不想被让其他类继承,就可以用final修饰。final类中的成员变量可以根据需要用final修饰,不过final类的所有的成员方法都会被隐式的指定为final修饰

使用final修饰类时要慎重考虑下,该类是否真的不会被用来继承或者出于安全的考虑,否则尽量不要用final修饰类

final和private的区别

  • final修饰的类可以访问;

    private不可以修饰外部类,但可以修饰内部类(其实把外部类私有化是没有意义的)

  • final修饰的方法不可以被子类重写;

    private修饰的方法表面上是可以被子类重写的,其实是不可以的,子类是看不到父类的私有方法的

  • final修饰的变量只能在显示初始化或者构造函数初始化的时候赋值一次,以后不允许修改;

    private修饰的变量,也不允许直接被子类或一个包中的其他类访问或修改,但是他可以通过set和get方法对其进行改值和取值

深入理解final关键字

1、final变量和普通变量的区别

final修饰类的成员变量时,成员变量必须在定义时或者构造器中进行初始化赋值,一定被初始化赋值后,就不能再赋值了。

先看段代码:

public class FinalTest {

    public static void main(String[] args) {
        String a = "java11";
        final String b = "java";
        String c = "java";
        String d = b + 11;
        String e = c + 11;
        System.out.println((a == d));
        System.out.println((a == e));
    }
}

输出结果:

true
false

为什么输出结果是这样的?我们来分析分析:

  • final修饰变量b,在编译期就能确定变量b的确切值,则编译器会把变量b当做常量来使用。只要用到变量b的地方,就相当于直接访问变量b的常量值,而不需要在运行期才知道具体的变量值。所以我们可以知道,变量b的值在编译期间就能知道,是java11,这样System.out.println((a == d))输出true也就好理解了

  • 变量c没有用final来修饰,需要在运行期调用时才能知道具体的值,这样System.out.println((a == e))输出false

这里要注意的是,只有在编译期能明确知道final变量值的情况下,编译器才会进行这样的优化。

如下这段代码则不会进行优化:

public class FinalTest2 {

    public static void main(String[] args) {
        String a = "java11";
        final String b = getLanguage();
        String c = b + 11;
        System.out.println((a == c));
    }

    public static String getLanguage() {
        return "java";
    }
}

输出结果:

false

2、被final修饰的引用变量指向的对象内容可变吗?

文章上面的内容有提到过:final修饰对象引用类型的变量时,该变量一旦初始化之后就不能再指向其他的对象。那么,该引用变量指向的对象内容可以改变吗?

我们来看一段代码:

public class FinalTest3 {

    public static void main(String[] args) {

        final Demo demo = new Demo();
        ++demo.i;
        System.out.println(demo.i);
    }


}

class Demo {

    public int i = 0;
}

输出结果:

1

可以看出,final修饰的对象引用类型变量,指向的对应内容是可以被改变的。

3、final和static的区别

final和static这两个关键字,大家很容易混淆,这样说明下:

  • static修饰成员变量时,只是在内存中保存一个副本,关于static关键字的详细介绍,可以参考我的另外一篇博客static关键字详解

  • final修饰变量时,只是让变量的值不可变

我们来看一下这段代码:

public class FinalTest4 {

    public static void main(String[] args) {
        MyClass1 myClass1 = new MyClass1();
        MyClass1 myClass2 = new MyClass1();
        System.out.println(myClass1.i);
        System.out.println(myClass1.j);
        System.out.println(myClass2.i);
        System.out.println(myClass2.j);

    }
}

class MyClass1 {
    public final double i = Math.random();
    public static double j = Math.random();
}

输出结果为:

0.14420367652868182
0.8907081784319505
0.77280060728079
0.8907081784319505

可以看出,static修饰的变量j的值是相同的,没有变化。如果我们对final修饰的变量i进行赋值是编译报错的
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值