关于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
,要进行修饰这些变量
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
吧
四、最后想说的话
我是半月,祝你幸福!!!