Java基础面试题5:final关键字

1、简述final的作用

可以用来修饰:类 、变量、方法,不能用来修饰抽象类和接口。

final修饰类

当用final修饰一个类时,表明这个类不能被继承(不能有子类)。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法(因为类不能被继承,所以方法不能被重写)。

final类不能被继承,因此final类的成员方法没有机会被覆盖,默认都是final的。在设计类时候,如果这个类不需要有子类,类的实现细节不允许改变,并且确信这个类不会再被扩展,那么就设计为final类

final修饰方法

当final修饰的方法表示此方法已经是“最后的、最终的”含义,亦即此方法不能被重写(可以重载多个final修饰的方法)。此处需要注意的一点是:因为重写的前提是子类可以从父类中继承此方法,如果父类中final修饰的方法同时访问控制权限为private,将会导致子类中不能直接继承到此方法,因此,此时可以在子类中定义相同的方法名和参数,此时不再产生重写与final的矛盾,而是在子类中重新定义了新的方法。(注:类的private方法会隐式地被指定为final方法。)
final方法不能被子类的方法覆盖,但可以被继承。

final不能用于修饰构造方法

构造器不是通过继承得到的,所以没有必要把它声明为final的
在这里插入图片描述

final修饰变量

final修饰成员变量

另外final修饰一个普通成员变量(属性),必须要显示初始化。这里有两种初始化方式,(1.在申明的时候给其赋值,否则必须在其类的所有构造方法中都要为其赋值,或者在非静态代码块中赋值)

  final int a=0;//final修饰一个成员变量(属性),必须要显示初始化

在这里插入图片描述
在非静态代码块中初始化

final int a;
    {
        a=0;
    }

在构造器中初始化

 final int a;
    public finalTest(int a) {
        this.a = a;
    }

final修饰一个静态成员变量(属性),可以在静态代码块中初始化,或在定义时初始化

定义时初始化静态成员变量

    final static int a=0;

在静态代码块中初始化静态成员变量

  final static int a;
    
    static{
        a=0;
    }

final静态成员变量不能在构造器初始化哦
在这里插入图片描述

final修饰局部变量

final修饰一个局部变量,因为系统不会为局部变量进行初始化,局部变量必须由程序员显示初始化。因此使用final修饰局部变量时,即可以在定义时指定默认值((后面的代码不能对变量再赋值),也可以不指定默认值,而在后面的代码中对final变量赋初值(仅一次)

如下图,局部变量在使用前必须初始化
在这里插入图片描述
在这里插入图片描述

final修饰基本类型数据和引用类型数据
  • 当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化

把i定义为final的1,就不能再改变i的值了
在这里插入图片描述

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

就是说,final修饰一个引用,这个引用就不能改变指向了,因为引用是保存的地址值嘛,也就是说这个引用指向的地址不能改变,但是这个地址里面的值只要不是final修饰的是可以改变的,比如下面,arr已经指向了一个初始化的数组,就不能再把arr置空,但是arr指向的数组里面的数值仍然可以改变
在这里插入图片描述

2、为什么局部内部类和匿名内部类只能访问局部final变量

意思就是局部内部类和匿名内部类要访问局部变量,局部变量得加final,但是IDEA对于内部内访问的局部变量会默认加上final关键字

首先需要知道的一点是:内部类和外部类是处于同一个级别的,内部类不会因为定义在方法中就会随着方法的执行完毕就被销毁。
这里就会产生问题:当外部类的方法结束时,局部变量就会被销毁了,但是内部类对象可能还存在(只有没有人再引用它时,才会死亡)。这里就出现了一个矛盾:内部类对象访问了一个不存在的变量。为了解决这个问题,就将局部变量复制了一份作为内部类的成员变量,这样当局部变量死亡后,内部类仍可以访问它,实际访问的是局部变量的"copy"。这样就好像延长了局部变量的生命周期
将局部变量复制为内部类的成员变量时,必须保证这两个变量是一样的,也就是如果我们在内部类中修改了成员变量,方法中的局部变量也得跟着改变,怎么解决问题呢?
就将局部变量设置为final,对它初始化后,我就不让你再去修改这个变量,就保证了内部类的成员变量和方法的局部变量的一致性。这实际上也是一种妥协。使得局部变量与内部类内建立的拷贝保持一致

匿名内部类

public class finalTest {
    public static void main(String[] args) {
        tes(1);
    }   
   static void tes(  int b)//b是形参,也是局部变量
    {
        int a=10;
        //匿名内部类
        new Thread(){public void run(){
            System.out.println(a);//匿名内部类访问变量a
            System.out.println(b);//匿名内部类访问变量b
        }}.start();
    }
}

我的局部变量a,b都内有加final,且编译不报错,现在运行看看

在这里插入图片描述

为什么也能运行呢?其实是IDEA在检测到内部类之后给局部变量默认加了final关键字,比如,现在我们来尝试改变a和b的值

在这里插入图片描述

在这里插入图片描述

局部内部类

在这里插入图片描述

class OutClass{
    private int age=12;
    public void outPrint( final int x)
    {
        class Inclass{
            public void InPrint()
            {
                System.out.println(x);
                System.out.println(age);//访问成员变量不需要final修饰
            }
        }
        new Inclass().InPrint();
    }

}

final finally finalize()的区别

final如上述

finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),经常被用在需要释放资源的情况下。
只有与finally对应的try语句块得到执行的情况下,finally语句块才会执行。如果执行try语句块之前已经返回或抛出异常,try对应的finally语句并不会执行
如果我们在 try 语句块中执行了 System.exit (0) 语句,终止了 Java 虚拟机的运行,finally语句也不会执行。

finalize()是在java.lang.Object里定义的,也就是说每一个对象都有这么个方法。这个方法在gc启动,该对象被回收的时候被调用。finalize()是Object里面的一个方法,当一个堆空间中的对象没有被栈空间变量指向的时候,这个对象会等待被java回收。其实gc可以回收大部分的对象(凡是new出来的对象,gc都能搞定,一般情况下我们又不会用new以外的方式去创建对象),所以一般是不需要程序员去实现finalize的。
特殊情况下,需要程序员实现finalize,当对象被回收的时候释放一些资源,比如:一个socket链接,在对象初始化时创建,整个生命周期内有效,那么就需要实现finalize,关闭这个链接。
  使用finalize还需要注意一个事,调用super.finalize();
 一个对象的finalize()方法只会被调用一次,而且finalize()被调用不意味着gc会立即回收该对象,所以有可能调用finalize()后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会调用finalize(),产生问题。 所以,推荐不要使用finalize()方法,它跟析构函数不一样。

参考

String属于基础的数据类型么?
[Java基础]Java中字符串string属于什么数据类型?
修饰符abstract、static、final为何不用于修饰构造方法?
Java 面试系列 ——1.Java基础 final 关键字

final、finally与finalize的区别

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值