看起来像三兄弟的final、finally与finalize,其实一点联系都没有

88 篇文章 10 订阅
24 篇文章 1 订阅

这三个就像迪丽热巴、古力娜扎、马尔扎哈一样,明明是完全不相关的三个人(迪丽热巴我女神最美!),每次面试总是把这三者放在一起,可能是它们名字非常像吧,今天让我们聊一聊final、finally、finalize这三个各自的使用场景。
在这里插入图片描述

另外本人整理了20年面试题大全,包含spring、并发、数据库、Redis、分布式、dubbo、JVM、微服务等方面总结,下图是部分截图,需要的话点这里点这里,暗号CSDN。

在这里插入图片描述

一、final

在这里插入图片描述

在java中,final可以用来修饰类,方法和变量(成员变量或局部变量)。下面将对其详细介绍。

1.1 修饰类

当用final修饰类的时,表明该类不能被其他类所继承。当我们需要让一个类永远不被继承,此时就可以用final修饰,但要注意:

final类中所有的成员方法都会隐式的定义为final方法。

1.2 修饰方法

使用final方法的原因主要有两个:

(1) 把方法锁定,以防止继承类对其进行更改。

(2) 效率,在早期的java版本中,会将final方法转为内嵌调用。但若方法过于庞大,可能在性能上不会有多大提升。因此在最近版本中,不需要final方法进行这些优化了。

final方法意味着“最后的、最终的”含义,即此方法不能被重写。

注意:若父类中final方法的访问权限为private,将导致子类中不能直接继承该方法,因此,此时可以在子类中定义相同方法名的函数,此时不会与重写final的矛盾,而是在子类中重新地定义了新方法。

1.3 修饰变量

final成员变量表示常量,只能被赋值一次,赋值后其值不再改变。类似于C++中的const。

当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。本质上是一回事,因为引用的值是一个地址,final要求值,即地址的值不发生变化。

final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。

当函数的参数类型声明为final时,说明该参数是只读型的。即你可以读取使用该参数,但是无法改变该参数的值。

二、 finally

在这里插入图片描述

finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),经常被用在需要释放资源的情况下。(×)(这句话其实存在一定的问题)

finally是异常处理中的一个关键字,通常的结构是这样的:

try{
return a;
 } catch(Exception ex){
return b;
 } finally{
return c;
 },

它一般用于资源释放,比如我们可以在finally块中关闭数据库连接,在这个结构中不管异常有没有发生finally中的代码都会执行。

但是finally中的代码不是一定会被执行。在以下情况下不会执行finally中的代码:

  1. 在进入try块之前程序发生异常。

  2. 在try块中调用了System.exit(0)终止了虚拟机的运行。

  3. 在try块或catch块中程序被中断,比如说死机。

我们再来看下面这个例子:

public class Demo02 {
public static void main(String[] args) {
 System.out.println(methd());
  }
public static int methd(){
 int num = 1;
  try{
   return num;
}catch (Exception ex){
   return 0;
}finally {
  num++;
   }
  }
 }

程序运行的结果为:1

这个例子中finally中的代码究竟是在return前还是return后执行的呢?你可能认为是在return 前执行的,我们来看一下程序执行的过程,执行到try块中的return num的时候num的值1会被作为返回值存放到栈中但是这时程序并不会返回,而是去执行num++,num的值变为2,然后程序返回结束,此时返回的还是栈中的num值1。

我们再来看另一个例子:

public classDemo02 {
 public static voidmain(String[] args) {
  System.out.println(methd());
   }
 public static intmethd(){
  intnum = 1;
 try{
  returnnum;
}catch(Exception ex){
  return0;
}finally{
  return2;
   }
  }
 }

这段程序的运行结果为2

在程序执行到try块中的return num时将num中的值1作为返回值保存在栈中,然后执行finally块中的代码,return 2,此时栈中的返回值变为了2,所以最后的结果为2.

总结一下:

  1. finally在try块和catch块return执行后,返回前执行。

  2. 如果finally中没有return,则其执行结果不影响try和catch中已确定的返回值。

  3. 如果finally中有return,则其执行结果会直接返回。

三、finalize

在这里插入图片描述

finalize()是在java.lang.Object里定义的,也就是说每一个对象都有这么个方法。这个方法在gc启动,该对象被回收的时候被调用。其实gc可以回收大部分的对象(凡是new出来的对象,gc都能搞定,一般情况下我们又不会用new以外的方式去创建对象),所以一般是不需要程序员去实现finalize的。

特殊情况下,需要程序员实现finalize,当对象被回收的时候释放一些资源,比如:一个socket链接,在对象初始化时创建,整个生命周期内有效,那么就需要实现finalize,关闭这个链接。

使用finalize还需要注意一个事,调用super.finalize();

一个对象的finalize()方法只会被调用一次,而且finalize()被调用不意味着gc会立即回收该对象,所以有可能调用finalize()后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会调用finalize(),产生问题。 所以,推荐不要使用finalize()方法,它跟析构函数不一样。

最后:

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

下面的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2020收集的一些大厂的面试真题(都整理成文档,小部分截图),有需要的可以点击进入暗号CSDN

在这里插入图片描述

在这里插入图片描述

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值