详解Java关键字final

作者:星河入梦丶 时间:2023-11-29 09:10:27 

一、常见问题

  • 所有的final修饰的字段都是编译期常量吗?

  • 如何理解private所修饰的方法是隐式的final?

  • 说说final类型的类如何拓展?比如String是final类型,我们想写个MyString复用所有String中方法,同时增加一个新的toMyString()的方法,应该如何做?

  • final方法可以被重载吗?可以

  • 父类的final方法能不能够被子类重写?不可以

  • 说说final域重排序规则?

  • 说说final的原理?

  • 使用 final 的限制条件和局限性?

二、final修饰类

当某个类的整体定义为final时,就表明了你不能打算继承该类,而且也不允许别人这么做。即这个类是不能有子类的。
注意:final类中的所有方法都隐式为final,因为无法覆盖他们,所以在final类中给任何方法添加final关键字是没有任何意义的。

三、final修饰方法

类中所有private方法都隐式地指定为final的,由于无法取用private方法,所以也就不能覆盖它。可以对private方法增添final关键字,但这样做并没有什么好处。


public class Base {
   private void test() {
   }
}

public class Son extends Base{
   public void test() {
   }
   public static void main(String[] args) {
       Son son = new Son();
       Base father = son;
       //father.test();
   }
}

Base和Son都有方法test(),但是这并不是一种覆盖,因为private所修饰的方法是隐式的final,也就是无法被继承,所以更不用说是覆盖了,在Son中的test()方法不过是属于Son的新成员罢了,Son进行向上转型得到father,但是father.test()是不可执行的,因为Base中的test方法是private的,无法被访问到。

四、final方法是可以被重载的

我们知道父类的final方法是不能够被子类重写的,那么final方法可以被重载吗? 答案是可以的,下面代码是正确的。


public class FinalExampleParent {
   public final void test() {
   }

public final void test(String str) {
   }
}

修饰参数
Java允许在参数列表中以声明的方式将参数指明为final,这意味这你无法在方法中更改参数引用所指向的对象。这个特性主要用来向匿名内部类传递数据。

五、修饰变量


public class Test {
   //编译期常量
   final int i = 1;
   final static int J = 1;
   final int[] a = {1,2,3,4};
   //非编译期常量
   Random r = new Random();
   final int k = r.nextInt();

public static void main(String[] args) {

}
}

k的值由随机数对象决定,所以不是所有的final修饰的字段都是编译期常量,只是k的值在被初始化后无法被更改。

六、static final

一个既是static又是final 的字段只占据一段不能改变的存储空间,它必须在定义的时候进行赋值,否则编译器将不予通过。


public class finaltest
{
   //Random对象r
   static Random r = new Random();
   //生成随机数k
   final int k = r.nextInt(10);
   //生成随机数k2
   static final int k2 = r.nextInt(10);

public static void main(String[] args) {

finaltest t1 = new finaltest();

System.out.println("k="+t1.k+" k2="+t1.k2);

finaltest t2 = new finaltest();

System.out.println("k="+t2.k+" k2="+t2.k2);
   }
}

k=2 k2=7
k=8 k2=7
我们可以发现对于不同的对象k的值是不同的,但是k2的值却是相同的,这是为什么呢? 因为static关键字所修饰的字段并不属于一个对象,而是属于这个类的。也可简单的理解为static final所修饰的字段仅占据内存的一个一份空间,一旦被初始化之后便不会被更改。

七、black final

Java允许生成空白final,也就是说被声明为final但又没有给出定值的字段,但是必须在该字段被使用之前被赋值,这给予我们两种选择:

  • 在定义处进行赋值(这不叫空白final)

  • 在构造器中进行赋值,保证了该值在被使用前赋值。

这增强了final的灵活性。


final int i1 = 1;

final int i2;//空白final

public finaltest() {
       i2 = 1;
   }
   public finaltest(int x) {
       this.i2 = x;
   }

可以看到i2的赋值更为灵活。但是请注意,如果字段由static和final修饰,仅能在定义处赋值,因为该字段不属于对象,属于这个类。

八、final域重排序规则

上面我们聊的final使用,应该属于Java基础层面的,当理解这些后我们就真的算是掌握了final吗? 有考虑过final在多线程并发的情况吗? 在java内存模型中我们知道java内存模型为了能让处理器和编译器底层发挥他们的最大优势,对底层的约束就很少,也就是说针对底层来说java内存模型就是一弱内存数据模型。同时,处理器和编译为了性能优化会对指令序列有编译器和处理器重排序。那么,在多线程情况下,final会进行怎样的重排序? 会导致线程安全的问题吗? 下面,就来看看final的重排序。

来源:https://blog.csdn.net/qq_37151886/article/details/117229178

标签:Java,关键字,final
0
投稿

猜你喜欢

  • 详解SpringBoot构建的Web项目如何在服务端校验表单输入

    2021-08-22 23:51:59
  • 利用C语言实现一个最简单的飞机游戏

    2022-12-11 15:17:22
  • Java截取字符串的几种方法示例

    2023-11-29 12:36:32
  • 浅析C#中数组,ArrayList与List对象的区别

    2022-03-12 00:41:30
  • Android应用开发中WebView的常用方法笔记整理

    2021-06-29 04:29:39
  • unity3d实现七天签到功能

    2023-01-05 08:57:21
  • C#读写操作app.config中的数据应用介绍

    2021-07-25 21:33:19
  • Java Socket使用加密协议进行传输对象的方法

    2023-11-28 12:47:44
  • Android使用TransitionDrawable渐变切换多张图片

    2023-01-08 16:27:22
  • c#中CAD文件读取实例

    2023-07-23 19:37:59
  • C++之异常处理详解

    2023-04-10 10:22:00
  • Kotlin启动协程的三种方式示例详解

    2023-06-07 02:58:53
  • C#实现简单俄罗斯方块

    2023-06-18 07:18:36
  • C#服务器NFS共享文件夹搭建与上传图片文件的实现

    2023-01-31 01:19:49
  • Android使用AudioManager修改系统音量的方法

    2023-11-20 09:10:00
  • Java通过底层原码了解数组拷贝

    2021-10-07 12:47:47
  • C#随机生成Unicode类型字符串

    2023-12-05 08:42:29
  • Java ForkJoin框架的原理及用法

    2022-03-13 05:26:51
  • 100-200之间所有素数求和程序代码(二个版本)

    2022-07-03 18:53:58
  • springcloud使用Hystrix进行微服务降级管理

    2023-02-02 06:51:30
  • asp之家 软件编程 m.aspxhome.com