• 你真的知道final关键字吗?


    概述

    final在英文中是最终的,不可更改的。在Java中final修饰变量,函数和类,就像这个单词的意思,一旦使用赋值之后不可更改。

    final修饰的变量不可以被改变

    finalTest类

    public class finalTest
    {
        private String test = "test";
        //final修饰的成员变量 第一种赋值方式
        private final int a = 6;
    
        private final int b;
    
        private final int c;
    
        //final修饰的静态成员变量 第一种赋值方式
        private final static int e = 6;
    
        private final static int f;
    
        public finalTest()
        {
            //final修饰的成员变量 第二种赋值方式
            b = 5;
        }
    
        {
            //final修饰的成员变量 第三种赋值方式
            c = 5;
        }
    
        static
        {
            //final修饰的静态成员变量 第二种赋值方式
            f = 6;
        }
    
        public void test(final int g)
        {
            //final 修饰的局部变量第一种方式
            final int d = 10;
    
            //final 修饰的局部变量第二种赋值方式
            final int h;
            h = 11;
    
            //调用此函数的已经进行赋值,再次赋值会报错
            //g = 66;
        }
        @Override
        public String toString()
        {
            return test;
        }
    
        public static void main(String[] args)
        {
            final finalTest finalTest = new finalTest();
            //final修饰,无法被改变
            //finalTest = null;
            System.out.println(finalTest);
            finalTest.test = "test2";
            System.out.println(finalTest);
        }
    }

    输出

    test
    test2

    final修饰基本数据类型,不能对基本数据类型重新赋值,基本数据类型变量不能被改变。但final修饰引用类型变量,不变的仅仅是他的一个引用,只要引用地址不变,他里面的成员变量是可变的。

    final修饰的函数不可以被重写

    finalTest类

    public class finalTest
    {
        public final void test()
        {
            System.out.println("父类");
        }
    }
    
    class finalTestChild extends finalTest
    {
    //    @Override
    //    public void test()
    //    {
    //
    //    }
        //final修饰的函数可以被重载
        public void test(int a)
        {
            System.out.println("重载");
        }
    }

     

    父类被final修饰的函数是无法被子类重写的,但final修饰的函数可以被重载。

    final修饰的类不可以被继承

    最典型是的例子是Java的String类,打开String类发现String类是被final所修饰。

    finalTest类

    继承一个被final修饰的父类,就会报错。很明显Java设计人员不希望我们对String类进行修改,个人理解是因为String类过于强大,Java的设计人员出于安全考虑,不希望它有子类。 因为这样可能危及到系统安全。所以final类中所有的类都隐式指定为是final的,无法覆盖他们,我们只能使用他规定的函数。所以当我们希望自己的类不被人继承时,就可以指定为final。

    final的作用

    1. 效率,JVM和Java都会缓存final变量并对函数,和类进行优化。
    2. 设计和安全,上"锁",不希望自己的类和函数被人随意改变。

    final的安全发布

    创建一个对象,大致可以分为三个步骤

    1. 分配内存空间
    2. 将引用指向分配的内存空间
    3. 调用构造函数来初始化对象

    这三个步骤不是原子的,执行到第二部,没进行初始化,此时如果这个对象能被当前范围之外的代码所使用,因为这时对象已经不是null了,被其他代码访问,会得到一个错误的结果。这就是不安全的发布。所谓安全发布,简单理解就是对象的创建能够保障在被别人使用前,完成数据的构造设置,或者说一个对象使用时,已经进行初始化。但是Java对此并没有进行保障,需要自己进行保障设置,如锁机制等。

    对于final,当创建一个对象时,使用final关键字能够使得另一个线程不会访问到处于"部分创建"的对象。

    1. 当构造函数退出时,final字段的值保证对访问构造对象的其他线程是可见的。
    2. 一旦对象引用对其他线程可见,则其final成员也必须正确赋值。

    所以借助final,就如同是你对对象的创建访问加锁了一样,天然保障了对象的安全发布

    总结

    许多并发错误都是没理解共享对象的既定规则,当发布一个对象时,必须明确说明对象的访问方式。

  • 相关阅读:
    git 基础操作 && 在"develop"分支修改动但不想提交切换到"master"分支(最后)
    html、css面试题 持续更新中......
    JS面试题 持续更新中......
    盒子模型
    Tomcat环境设置及第一个JSP程序实现
    嵌入式V3s交叉编译 tslib和QT4.8.7,并使用Qt Creator编译项目
    嵌入式全志V3s荔枝派板卡移植 aircrack-ng
    为嵌入式全志V3s荔枝派板卡添加USB MT7601U(小米随身WIFI)驱动
    为嵌入式mplayer移植添加ALSA音频驱动(全志V3s荔枝派zero)
    Makefile知识点总结
  • 原文地址:https://www.cnblogs.com/dslx/p/10592120.html
Copyright © 2020-2023  润新知