为什么匿名内部类不能使用方法的局部变量,可以使用方法的 final 常量?
不加 final
局部变量用 final 修饰
本质(生命周期)
在方法执行的时候是借助栈来完成的,JVM 在执行我们的方法时,会把执行的方法作为一个栈帧压入栈。我们方
法里的局部变量被存储在执行方法所对应的栈帧的局部变量表中。这就意味着我们局部变量的生命周期是在所执行的方法还留在栈中,一旦这个方法弹出栈,局部变量也对应着被回收(栈是可以自动回收,不像堆需要垃圾回收器)。而方法里的匿名内部类由于是一个类的对象,它位于堆中,生命周期由堆来管理。所以这就导致了局部变量和匿名内部类对象的生命周期不一致的现象。可能方法执行完了,释放了匿名内部类所需要的局部变量,它的匿名内部类对象调用的时候就会出现问题。为了解决这个问题,我们可以加 final,使局部变量变为一个常量,这样在编译时就确定了,常量的生命周期往往是足够长,所以就不会出现匿名内部类对象调用时所需要的值已经被回收这种现象。
为什么非静态内部类不可以有静态方法、静态属性?
本质
非静态内部类
加载时间:
创建实例的时候
静态内部类
加载时间:
被使用时
static(静态)
static
类型的属性和方法,在类加载的时候就会存在于内存中。
我们还是从生命周期来理解这个问题。非静态内部类并不随着外部类的加载而加载,而是在创建实例的时候进行加载。如果一个非静态内部类如果具有静态的属性或者方法,这就意味着这个类还不存在,你就可以使用静态方法或属性。这明显和 static 的定义不符合。
如果你想在内部类使用静态属性或方法,只需要用 static 修饰这个内部类即可,这样外部类加载的时候会把内部类也加载到内存中,这样类存在了,当然你就可以使用静态方法或属性了。
内部类加载
加载一个类时,其内部类不会同时被加载。
一个类被加载,当且仅当其某个静态成员(静态域、构造器、静态方法等)被调用时发生。