JAVA 中内部类的一些用法,以及内部类访问外部变量为什么需要final修饰
几个小问题,我们想想看:
- 内部类访问成员变量,该成员变量需要 final修饰吗?为什么?
- 不需要
- 内部类访问方法的局部变量,该局部变量需要final修饰吗?为什么?
- 需要
接下来我们来解答这两个问题
先解释说明 上面第2个问题: 内部类访问方法的局部变量
在java8出现之前,内部类的写法,我们经常这样写:写在某个类中,或者某个类的方法中,或者匿名内部类。但是使用内部内部类经常遇到一个问题,就是内部类有时要访问到方法中的局部变量,或类变量,导致需要变量申明为 final属性。
为什么会这样呢,不申明fianl属性,编译就报错。
下面的doAction()方法中,内部类Myclass 方法 doPrint 使用了 局部变量age,和 类成员变量 sex, 此时 age是一个final变量,sex不是。
1. 局部变量 age由于 在方法doAction内,当doAction方法执行完,该变量就需要被回收,但是又由于 该局部变量又在内部类中使用了,并且内部类并不会因为一个方法的调用结束而结束,这就出现了 矛盾。
所以 JAVA中的解决办法是,内部内中使用的局部变量,会copy一份出来,在内部类中使用,这样即使局部变量回收了,也不影响内部类的使用。但是copy出两份就会引入一个问题,如何保持这两份数据的一致呢? 所以就引入final属性来进行修饰,
保持这个局部变量初始赋值后就不能更改了。
这是一种妥协的解决办法吧
再来看 内部类访问成员变量
2. 成员变量sex 也在内部类的方法中使用,但是就是因为sex是一个成员变量,也就是类变量(类变量是在类回收的时候才回收), 所以他的生命周期比内部类长,即使内部类回收了,成员变量也不会回收。所以类成员变量不需要final修饰
private String sex = "male"; // 成员变量
public void doAction(String[] args) {
String name = "张三";
final int age = 18; // MyClass内部类使用了age变量,所以 age是 final 变量
class MyClass{
public void doPrint(String name) {
System.out.println(name + " " + age + " " + sex);
}
}
new MyClass().doPrint(name);
name = "张忌";
// age = 20; // 因为是final变量,所以重新赋值会编译报错
sex = "female";
}
public void doRun(String[] args) {
final String partment = "武当派"; // Runnable 匿名内部类使用了partment 变量,所以 partment 是 final 变量
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello "+ partment +"(a) !");
}
}).start();
// 或者 也经常这样写
new Thread(() -> System.out.println("hello "+ partment +"(b) !")).start();
// partment = "运营部"; // 因为是final变量,所以重新赋值会编译报错
}