Java语言中final关键字_JAVA语言中的final关键字解析

本文主要向大家介绍了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频道!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值