Java基础知识总结:浅谈final关键字的使用

Final关键字的含义

     在Java中,final关键字意思为最终的,不可改变的,final是一个非访问修饰符,不同于public、private等,final关键字一般主要作用于修饰类、成员变量、方法以及修饰方法参数,final作用于不同的地方时所代表的含义并不相同。

1. final修饰类

当使用final关键字修饰一个类时,则这个类不可以被继承即该类无子类,并且,该类的所有的方法将被默认修饰为final类型,但是,成员变量不会被修饰为final类型,在JDK中,所有包装类IntegerFloat等都是final类,所以我们没有办法继承包装类。

final修饰的类除了可以将该类表示为不可继承之外,还有一个作用就是将该类修饰为不可改变的类,将该类修饰为不可改变的类,一个好处就是,该类的所有的方法都不会被子类重载、重写,因为该类没有办法被继承,这样的话,在编译器进行优化时提供了更多的可能,一般来说,final修饰类时一般是修饰public类型,但是,顶层类(全局或包可见)、嵌套类(内部类或静态嵌套类)都可以用final来修饰,private也可以使用final来修饰,但是由于类的可见性已经限制了类不会被继承,所以使用final关键字的意义并不大,所以,一般final关键字大多数修饰的是public的类。

final与匿名内部类(参考自:https://www.cnblogs.com/cciejh/p/final-in-java.html

匿名类(Anonymous Class)虽然说同样不能被继承,但它们并没有被编译器限制成final。另外要提到的是,网上有许多地方都说因为使用内部类,会有两个地方必须需要使用 final 修饰符:

  1. 在内部类的方法使用到方法中定义的局部变量,则该局部变量需要添加 final 修饰符
  2. 在内部类的方法形参使用到外部传过来的变量,则形参需要添加 final 修饰符

原因大多是说当我们创建匿名内部类的那个方法调用运行完毕之后,因为局部变量的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量就会消亡了,但内部类对象可能还存在。 此时就会出现一种情况,就是我们调用这个内部类对象去访问一个不存在的局部变量,就可能会出现空指针异常。而此时需要使用 final 在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以继续使用,JVM 会持续维护这个引用在回调方法中的生命周期。

但是 JDK 1.8 取消了对匿名内部类引用的局部变量 final 修饰的检查

对此,theonlin专门通过实验做出了总结:其实局部内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,自己内部的方法调用的实际是自己的属性而不是外部类方法的参数。外部类中的方法中的变量或参数只是方法的局部变量,这些变量或参数的作用域只在这个方法内部有效,所以方法中被 final的变量的仅仅作用是表明这个变量将作为内部类构造器参数,其实final不加也可以,加了可能还会占用内存空间,影响 GC。最后结论就是,需要使用 final 去持续维护这个引用在回调方法中的生命周期这种说法应该是错误的,也没必要。

final关键字在效率上的作用主要可以总结为以下三点:

  • 缓存:final配合static关键字提高了代码性能,JVM和Java应用都会缓存final变量。
  • 同步:final变量或对象是只读的,可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
  • 内联:使用final关键字,JVM会显式地主动对方法、变量及类进行内联优化。

2. final修饰方法

在《Java编程思想》中这样介绍final关键字修饰方法:使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。

第一个原因将方法锁定:使用final关键字修饰的方法,不可以被重载,被重写,子类中也无法修改该方法,一般如果一个类功能已经十分完善不需要在子类中进行任何修改,可以将该方法使用final关键字修饰。

第二个原因提高效率主要是对于编译器而言:在早期的Java中是这样规定的,如果说将一个方法使用final关键字修饰,则表明同意编译器将针对该方法的调用都转化为内嵌调用(内联)。如果是内嵌调用,虚拟机不再执行正常的方法调用(参数压栈,跳转到方法处执行,再调回,处理栈参数,处理返回值),而是直接将方法展开,以方法体中的实际代码替代原来的方法调用。这样就减小了开销。但是由于虚拟机的不断更新,已经可以做到自己根据实际情况来确定是否内嵌调用,只不过,如果使用了final关键字,则更加显示的提醒虚拟机进行内嵌调用。

当使用private修饰变量时会被隐形的使用final关键字修饰,同样不可以重写,所以,当变量使用private修饰时使用final的意义不大

final和abstract永远不会同时出现,因为,如果使用abstract修饰一个类时,该类变成抽象类,,抽象类必须要在子类中进行具体实现,但是final是不可以被子类继承的,这就互相矛盾了,方法也是同样的道理。

3.final修饰变量

当final关键字修饰类成员变量或局部变量时,表明该变量不可变,如果该变量是非引用变量,表明该值不可变,如果该变量是引用变量,则该变量不可以引用至其他对象,但是,可以更改引用的对象的内部状态。

当一个变量被final修饰时,必须进行初始化,否则会出现编译错误,初始化final变量时,可以在声明它时初始化final变量。这种方法是最常见的。如果在声明时未初始化,则该变量称为final变量

下面是初始化空final变量的两种方法。

可以在instance-initializer块 或内部构造函数中初始化空的final变量。如果您的类中有多个构造函数,则必须在所有构造函数中初始化它,否则将抛出编译时错误。

可以在静态块内初始化空的final静态变量。

final修饰的变量不可以再次更改,但是,如final修饰的是一个引用变量,虽然说这个引用变量不可以重新引用至其他的对象,但是完全可以修改引用变量的内部状态,这与final变量的重新赋值是不一样的概念,这个属性叫做final变量的非传递性。

根据以下例子:

public static void main(String[] args) {
		final StringBuffer stringBuffer = new StringBuffer();
		stringBuffer.append(" Hello World ");
		System.out.println(stringBuffer);
		stringBuffer.append(" change World ");
		System.out.println(stringBuffer);
}

输出结果如下:

可以看到,引用变量可以修改内部状态,并且不会出现编译错误,但是,如果我加入代码:stringBuffer = new StringBuffer();,此时就会出现编译错误,因为这个时候,stringBuffer引用的不再是原有的对象,而是引用了一个全新的对象,相当于修改了final关键字修饰的变量,就会出现编译错误。

数组也是同样的道理,因为在Java中,数组就是对象。

在方法/构造函数/块中创建final变量时,它被称为局部final变量,并且必须在创建它的位置初始化一次。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 第6关中的"final"关键字Java语言中的一个修饰符,它可以用来修饰类、方法和变量。 1. 修饰类:使用final修饰的类不能被继承。 2. 修饰方法:使用final修饰的方法不能被子类重写。 3. 修饰变量:使用final修饰的变量变为常量,一旦赋值后不能再次赋值。 使用final关键字时需要注意: 1. final修饰的类中所有方法都隐式为final。 2. final修饰的变量必须在声明时或构造器中赋值,否则编译错误。 3. 对于基本数据类型,final修饰的变量的值不能改变,对于引用数据类型,final修饰的变量引用的对象的内容可以改变. ### 回答2: finalJava中的一个关键字,它可以用于修饰类、方法和变量。在这里,我们主要讨论final在修饰变量时的用途和作用。 一、变量被final修饰时具有不变性 当一个变量被final修饰时,它的值就不可以再次被修改,因此,我们称之为“常量”。final常量在定义时必须进行初始化,一旦被初始化后就不能再次改变了。 final修饰的变量通常采用大写字母命名,这样可以区分出普通的变量和常量。例如: final int MAX_LENGTH = 100; 这里我们定义了一个常量MAX_LENGTH,它的值为100,无论什么时候都不再改变。 二、final关键字可以提高程序的效率 使用final修饰变量时,编译器会对其进行优化,避免变量被重复赋值。 例如,在循环中使用final修饰的变量: for (final int i = 0; i < 100; i++) { // do something } 在这个循环中,i被final修饰后,编译器会在每次循环时将i的值缓存起来,避免多次访问内存。这样可以有效地提高代码的执行效率。 三、final修饰的变量可以保证数据的安全性 假设一个变量被多个线程共享,如果没有使用final修饰,那么这个变量的值可能会被不同的线程修改。这样就会产生数据的混乱,导致程序出现错误。 而使用final修饰变量后,它的值不可变,线程间就不会产生数据冲突。因此,使用final修饰变量可以提高程序的健壮性和鲁棒性。 综上所述,final关键字可以用来定义常量,提高代码效率,并且保证数据的安全性。在实际编程中,应当合理使用final关键字,以提高程序的性能和稳定性。 ### 回答3: final关键字Java中有着非常重要的作用,它可以用于修饰类、方法和变量。对于final修饰的类,表示该类是不可继承的,也就是说不能派生子类来继承这个类。而对于final修饰的方法,表示该方法不能被重写,也就是说不能在子类中重新定义该方法。最后,对于final修饰的变量,表示该变量是一个常量,它的值在初始化后就不能再被改变了。 其实final关键字主要的作用就是用来保护程序的安全性和稳定性。比如final修饰的变量,可以避免在程序运行过程中意外的修改变量的值,从而提高程序的可靠性。 另外,final关键字还有一个很有用的作用,就是可以用来提高程序的运行效率。因为final修饰的变量在编译时就可以确定其值,所以在程序运行时就可以直接使用该变量的值,而不需要再进行运算,这样就可以提高程序的运行效率。 在使用final关键字时,需要注意一些细节问题。比如final修饰的变量必须在声明时或构造函数中初始化,并且不能再被修改。另外,如果一个类被声明为final,则该类中所有的方法都自动成为final方法,因为这些方法都不能被重写。 总之,final关键字Java中非常重要的一部分,它可以用来保护程序的安全性和稳定性,同时也可以提高程序的运行效率。在使用过程中,需要注意一些细节问题,避免出现错误。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值