深入Java Final

时间:2022-06-22 09:38:14 

JAVA关键字final用于修饰数据、方法或类,通常意味着“无法改变的”,既数据不能改变,方法不能覆盖,类不能继承。一般采用final有两种原因:设计和效率。而随着JAVA版本的更新,一些效率上的问题可以交由编译器和JVM处理。因此,采用final来解决效率问题就显得不是那么重要了。

Final修饰符大多运用于基本数据类型(primitive)域或者不可变(immutable)类的域(如果类中的所有方法方法都不会改变其对象,这种类就是不可变类。String就是一个不可变类)。

【final数据】

Final关键字用修饰数据主要有两种情况:

1. 编译期常量

2. 运行时初始化的值

对于编译期常量,指的是一个既是final又是static的域(依照惯例,编译期常量全部用大写字母命名,并且用下划线分隔各个单词),它只占据一段不能改变的存储空间。编译器可以将编译期常量代入到任何可能用到它的计算式中,也就是说,可以在编译时执行计算式,这相对减轻了运行时负担。编译期常量在定义时必须对它赋值(不一定是基本类型)。

运行时初始化的值,对于基本类型,final使得其值不可改变;而对于对象引用,final使得引用不可改变,即无法将其改为指向另一个对象,然而,对象本身却可以修改(适用于数组,数组也是对象)。


public class javaFinalData{

    private static final String TESTD = "test";
    public static final String TESTE = "test";
    public static final String[] TESTF = {"1","2"}; //非基本类型
    private static final String[] TESTG = new String[2];

    public static void main(String args[]){
        final int testA = 1;
        final String testB = "test";
        final int[] testC = {1,1,2,};
        System.out.println(testC[1]);
        testC[1] = 123;
        System.out.println(testC[1]);
    }
}


【未赋值的final域】

JAVA允许生成未赋值的final域,但是必须在域的定义处或者每个构造器中对final域进行赋值(有多少个构造器就必须赋值几次),确保在使用前被初始化。采用这种方式,可以使得final运用得更加灵活,在同一个类中,根据不同的对象赋予不同的值,却又保持不可改变的特性。


public class javaBlankFinal{
    private final int blank;

    public javaBlankFinal(){
        blank = 2011;
    }

    public javaBlankFinal(int temp){
        blank = 2012;
    }

    public javaBlankFinal(String temp){
        blank = 2014;
    }

    public static void main(String args[]){
        new javaBlankFinal();
    }
}


【final方法】

       使用final方法有两方面原因:一是将方法锁定,防止方法被覆盖,确保在继承中方法行为保持不变;二是将方法调用转为内联调用(inlining),以减少方法调用的开销。但是,在最近的版本中,JVM可以自行进行优化,因此无需使用final方法来处理效率问题。

       关于final方法,还有一点需要注意,类中所有的private方法都隐式地指定为final方法(也可以为其加上final修饰,但没有意义)。当你试图覆盖一个private方法,编译器并没有报错,但是,实际上你并没有覆盖该方法,只是生成了一个新方法。因为private方法是无法被外部类所访问的,当然就无法覆盖到它了。

       使用@Override注解可以防止上述问题。如程序所示:


class finalFunction{
    private void finalFunctionA(){
        System.out.println("finalFunctionA");
    }

    private final void finalFunctionB(){
        System.out.println("finalFunctionB");
    }

    final void finalFunctionC(){
        System.out.println("finalFunctionC");
    }

    void functionD(){}
}

class overrideFinalFunction extends finalFunction{
    //@Override   添加@Override注解可以识别是否是override
    public void finalFunctionA(){              
        System.out.println("override finalFunctionA");
    }

    public final void finalFunctionB(){
        System.out.println("override finalFunctionB");
    }

    //final void finalFunctionC(){}   //Cannot override the final method from finalFunction

    @Override  
    void functionD(){} //真正的override方法
}

public class javaFinalFunction extends finalFunction{
    public static void main(String args[]){
        finalFunction ff = new finalFunction();
        //ff.finalFunctionA();  //无法调用private方法
        //ff.finalFunctionB();

        overrideFinalFunction off = new overrideFinalFunction();
        off.finalFunctionA();   //public方法
        off.finalFunctionB();
    }
}

【final类】

使用final类一般是出于设计原因,不允许该类被继承。这样可以保证类的行为不会改变,或许还能避免一些安全危机。Final类中所有的方法都隐式指定为final方法,因此无法被覆盖(因为final类禁止继承,也就无法覆盖其类中的方法)。在Java核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止覆盖length()等方法。

对于final域来说,即使将一个类声明为final,类中的域不会自动成为final域。


final class finalClass{
    int testA = 2011;
}
//class extendFinalClassextends finalClass{}  //can not extendthe final class finalClass

public class javaFinalClass{
    public static void main(String args[]){
       finalClass fc = new finalClass();
       System.out.println(fc.testA);
       fc.testA = 2012;
       System.out.println(fc.testA);
    }
}

标签:java,final
0
投稿

猜你喜欢

  • 浅谈三分钟学习Java泛型中T、E、K、V、?的含义

    2022-09-01 20:12:38
  • Java垃圾回收器的方法和原理总结

    2022-06-27 07:11:46
  • 详解使用SSM实现简单工作流系统之实现篇

    2021-10-21 07:49:23
  • springboot自定义Starter的具体流程

    2022-01-26 05:08:06
  • MyBatis全局映射文件实现原理解析

    2021-06-21 17:01:29
  • C#四舍五入用法实例

    2021-07-20 02:49:20
  • SpringCloud可视化链路追踪系统Zipkin部署过程

    2023-11-27 04:34:06
  • swagger添加权限验证保证API(接口)安全性(两种方法)

    2023-11-27 18:58:33
  • Java 从互联网上爬邮箱代码示例

    2022-02-27 16:40:57
  • 浅析C#中数组,ArrayList与List对象的区别

    2022-03-12 00:41:30
  • springboot如何通过@PropertySource加载自定义yml文件

    2022-08-06 19:42:56
  • Spring bean对象实例化实现过程图解

    2023-01-02 07:32:13
  • Java并发编程之闭锁与栅栏的实现

    2022-01-09 15:00:12
  • java判断用户输入的是否至少含有N位小数的实例

    2021-06-01 02:56:42
  • java处理图片背景颜色的方法

    2023-11-27 04:38:20
  • c# 配置文件App.config操作类库的方法

    2023-01-19 10:34:37
  • springboot使用Mybatis-plus分页插件的案例详解

    2023-10-27 13:47:43
  • Java的System.getProperty()方法获取大全

    2023-11-10 20:12:12
  • SpringBoot2整合activiti6环境搭建过程解析

    2023-11-09 02:27:03
  • 通过实例解析java8中的parallelStream

    2022-04-17 12:59:37
  • asp之家 软件编程 m.aspxhome.com