关于final关键字的两个面试题

2023-03-03 14:32:19 浏览数 (2)

关于final关键字的两个面试题

一、介绍

final关键字常用,但真的了解它吗。我做一下记录,仅供参考

  • 简述final的作用
  • 为什么局部内部类和匿名内部类只能访问局部的final变量

二、简述final的作用

final是一个修饰符,表示最终的,不可被修改

  • 修饰类:表示类不可被继承,所以抽象类不能使用final关键字
  • 修饰方法:表示方法不能被重写,但是可以进行重载
  • 修饰变量:表示赋值后就不能修改该变量的值

修饰变量时,有几种情况

修饰成员变量时

代码语言:javascript复制
public class Demo {

    // 声明时直接赋值
    final int a = 1;

    // 在代码块中进行赋值
    final int b;
    {
        b = 2;
    }

    // 在构造函数中进行赋值
    final int c;
    public Demo(int c) {
        this.c = c;
    }
}

修饰局部变量时

代码语言:javascript复制
public class Demo0 {

    public static void main(String[] args) {
		final int a = 1;// 一旦赋值无法改变
        final int b;// 在声明时,可以不赋值
        b = 2;// 在使用前一定要进行赋值
        System.out.println(a   b);
    }
}

修饰静态变量时

代码语言:javascript复制
public class Demo {

    // 直接赋值
    static final int a = 1;
    
    // 在静态代码块中赋值
    static final int b;
    static {
        b = 2;
    }
    
}

修饰基本数据类型和引用类型时

代码语言:javascript复制
public class Demo {

    public static void main(String[] args) {
        final int a = 1;
        a = 2;// 不可修改
        
        final Person person = new Person("半月", 18);
        person.setName("半月无霜");// 可以进行修改,final声明的只是person这个局部变量
        person = new Person("半月无霜", 22);// 不允许修改
    }
}

@Data
@AllArgsConstructor
class Person {
    String name;
    int age;
}

三、局部内部类和匿名内部类

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

这的确是一个好问题,我们一起来看看

先简单写出局部内部类和匿名内部类,发现他们使用外部的变量时,外部变量都要用final修饰,不然idea直接爆红了。

Variable used in lambda expression should be final or effectively final 简单翻译一下:在lambda表达式中使用变量应该是final或者有效的final 还有局部内部类,也有这样的问题 Variable ‘number1’ is accessed from within inner class, needs to be final or effectively final 在内部类中访问number1,需要final或者有效的final

它提到了final,要进行修饰这些变量

代码语言:javascript复制
package com.banmoon.algorithm.order;

public class Demo {

    public static void main(String[] args) {
        Demo demo = new Demo();
        demo.test1(10);
        demo.test2(10);
    }

    public void test1(int number1){
        int number2 = 1;
        number1 = number1   number2;
        number2 = 10;
        final int finalNumber = number1;
        final int finalNumber1 = number2;
        new Thread(() -> {
            System.out.println(finalNumber);
            System.out.println(finalNumber1);
        }).start();
    }

    public void test2(int number1){
        int number2 = 1;
        number1 = number1   number2;
        number2 = 10;
        int finalNumber = number1;
        int finalNumber1 = number2;
        class InnerClass {
            public void print(){
                System.out.println(finalNumber);
                System.out.println(finalNumber1);
            }
        }
    }
}

为什么不能直接使用呢,原因也很简单。

因为,在进行编译java文件时,上面提到了内部类会生成独立的class文件。

那么问题随之而来,匿名内部类和局部内部类想要使用外部的变量该怎么办,编译时候它是怎么做的?它直接将外部的变量复制了一份在内部类中。

好的那么,问题又来了。外部类中有一份,内部类中也有一份,数据不一致该怎么办。干脆一刀切算了,直接使用final关键字吧。

像上面示例的27和28行,虽然它没有final修饰,但也可以编译通过,这两个变量已经不会再做更改了。不过在使用内部类的时候,还是得小心,最好还是加上final

四、最后想说的话

我是半月,祝你幸福!!!

0 人点赞