JAVA语言中的final关键字解析
小标 2018-10-12 来源 : 阅读 845 评论 0

摘要:本文主要向大家介绍了JAVA语言中的final关键字解析,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了JAVA语言中的final关键字解析,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。


 

我们有时会发现jdk的源码中经常出现final这个关键字,那么它到底有什么作用呢?只是一种规范?还是说在某种场景下有性能上的优化?


首先我们从字面意义上进行初步阐述,final的英文意思是:最终的,不可更改的。也就是说被final关键字修饰的“东西”至少具有某种不变的性质。事实上,我们可根据“东西”的类别来分别描述final关键字的作用。


一、修饰类(非抽象类)


若final关键字修饰类,则表示该类不能被继承,该类的成员方法无法被覆盖,但并不会默认加上final修饰符(反编译后或者利用反射机制可验证),只是说有提升效执行效率(被final修饰的效果之一)的作用。在设计类时候,如果这个类不需要有子类继承,那么就设计为final类。


二、修饰方法(非抽象方法)


若final关键字修饰方法,则表示该方法不能被子类覆盖(或者说被子类重写),但是可以被继承。此外,若方法被final修饰,那么编译器在遇到调用该方法时候会转入内嵌机制,以便提高执行效率。值得注意的是,类的私有成员方法也并不会默认加上final修饰符(反编译后或者利用反射机制可验证),只有提升效执行效率的作用(java早期版本中的私有方法必须显示加上final关键字来达到内嵌的效果,而在java2之后则无需加上final关键字,也会默认转入内嵌机制)。


三、修饰变量


final修饰变量是比较常用的,也是需要重点分析的。如果一个变量被final修饰,那么该变量在其作用域内不能被第二次赋值。变量可分为基本数据类型和引用类型。如果变量是基本数据类型,那么被final修饰后,该变量的值不能再更改;若变量是引用类型,则该变量的引用不可更改,但是被引用对象的属性可以更改。同时我们根据作用域的不同,大概可以分为如下几种情况:


1、作用域在类加载时


此种情况是成员变量同时被 static和final修饰,该成员变量成为常量。比如,类Car中的成员变量wheelNum(轮子数量),其值在类加载时就已初始化并不可更改(这个也很容易理解,因为汽车在生产之前便设计成固定的4个轮子)。


public class Car {

    public static final int wheelNum = 4;

}

   


2、作用域在生成类对象时


此种情况是成员变量仅被final修饰,该成员变量只是在对象生成后不可第二次赋值,但生成不同的对象时可以有不同的初始值。同样用汽车作为例子,类Car中的成员变量power(马力),其值可在生成不同对象时具有不同的初始值,一旦对象初始化后再试图对其值进行更改则会编译报错。


public class Car {

 

    public static final int wheelNum = 4;

     

    final double power = 100*Math.random() + 100;

     

    public static void main(String[] args) {

         

        Car car1 = new Car();

        System.out.println("car1-->wheelNum = " + car1.wheelNum);

        System.out.println("car1-->power = " + car1.power);

         

        Car car2 = new Car();

        System.out.println("car2-->wheelNum = " + car2.wheelNum);

        System.out.println("car2-->power = " + car2.power);

         

        //编译报错

        //car1.power = 120.00;

    }

}


运行结果:

car1-->wheelNum = 4

car1-->power = 186.2119546789537

car2-->wheelNum = 4

car2-->power = 184.25954192641169

   


3、作用域在方法内时


此种情况是局部变量仅被final修饰,该变量在方法内不能进行第二次赋值。除此之外,对于基本数据类型或字符串类型的变量,若被final修饰后,则该变量在编译时就已确定,也就是编译时常量,这时编译器可针对其所关联的代码进行内联优化,只是性能提升很微小。下面是网上比较通用的例子,用以分析局部变量是否被final修饰的进一步区别(除了赋值约束的区别)。



public class Test {

     

    public static void main(String[] args) {

         

        String s1 = "hello2";

        String s2 = "hello";

        final String s3 = "hello";

         

        String s4 = s2 + 2;

        String s5 = s3 + 2;

         

        System.out.println(s1 == s4);

        System.out.println(s1 == s5);

    }

}

 


运行结果:

false

true

   


为什么会出现这样的结果?我们首先回顾一下字符串常量池的知识:在执行String s1 = "hello2"语句的时候,“hello2”被压入字符串常量池中,并返回引用给s1;在执行String s4 = s2 + 2语句的时候,由于s2不是常量,编译器会new一个StringBuilder来分别添加s2和2的值,此时s4的值并不会添加到常量池中,其引用也不是字符串常量池中的地址,所以s1和s4并不是同一个对象,因此第一个判断为false。然而在执行String s5 = s3 + 2;语句的时候,由于s3是编译时常量,此时编译器意识到是常量与常量的连接,编译器会试图将连接后的值(“hello2”)压入字符串常量池中,如果该值在字符串常量池中已存,则返回该值在字符串常量池中的引用,所以s1和s5引用的是常量池中的同一个对象(“hello2”),因此第二个判断为true。


总结:


final关键字修饰类和变量的主要目的是想规范行为(性能提升可忽略,除非存在大量的基本数据类型运算,此时可用final修饰变量来达到性能提升的效果)。比如,被final修饰的类不可被子类继承,被final修饰的变量在其作用域内不可进行第二次赋值等等;而final关键字修饰方法,除了表示该方法无法被子类覆盖外,主要目的是为了使该方法转入内嵌机制,以便提高执行效率。但是,java2之后,类的私有成员方法无需加上final关键字,也会默认转入内嵌机制。因此,代码中使用final关键字其主要目的并不是提高代码的执行效率,而是想达到某种规范的效果。


          

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!


本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程