美文网首页
Final 和方法中的内部类

Final 和方法中的内部类

作者: Happioo | 来源:发表于2019-07-14 16:19 被阅读0次

    在 Java 的内部类的机制中,非 static 的内部类可以会持有外部类的 this 引用,因此可以访问外部类的资源,这一点还是挺自然的。

    但有一点一直让我觉得很神奇,就是方法中的内部类可以访问方法的 final 形参和 final 本地变量,如下:

    import javax.swing.*;
    
    public class FooGUI {
    
        public static void main(String[] args) {
            //initialize GUI components
            final JFrame jf = new JFrame("Hello world!"); //allows jf to be accessed from inner class body
            jf.add(new JButton("Click me"));
    
            // pack and make visible on the Event-Dispatch Thread
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    jf.pack(); //this would be a compile-time error if jf were not final
                    jf.setLocationRelativeTo(null);
                    jf.setVisible(true);
                }
            });
        }
    }
    

    这份代码取自维基百科,main 方法里创建的匿名内部类中引用了 main 方法里的 JFrame jf 本地变量。客户端编程,像 Android 应用开发中由于常常要设置监听,回调,所以经常会用到这个特性。

    那么这个特性是个什么原理呢,为什么能这么做呢,如果这个方法运行完了,它的栈帧就被移除了,里面的本地变量也都被清除了,这时候匿名内部类中再使用这个变量不会有问题吗?原来,在内部类中使用外部方法中的 final 本地变量和 final 形参时,编译器会去“捕获”它们,会存一份拷贝在内部类中,这样的话,即使方法的栈帧被清除了,内部类中仍然保存着它的拷贝,仍然能访问它。

    至于,为什么这些变量要被修饰成 final,主要是为了维持一致性。因为实际上内部类和外部方法用的不是同一份变量,但从外部看来,它们还得像是同一份变量,如果允许改动这些变量的话,很可能会出现不一致的情况,所以用 final 修饰它们,让它们是不可变的。

    在 Java 8 后,即使本地变量或方法参数不标记成 final,内部类中也能访问它们。但事实上,其实是和用 final 修饰一样的,同样还是不允许修改他们,只是不用 final 修饰而已。如果有修改它们的行为,那么编译时就会报错。这种变量称为 effectively final 变量。

    相关文章

      网友评论

          本文标题:Final 和方法中的内部类

          本文链接:https://www.haomeiwen.com/subject/fhfikctx.html