局部内部类能访问非final类型局部变量?

答案: 不能。

经过查看许多人给出的分析,得出我个人认为比较有说服力的原因:

为了克服局部内部类和局部变量的生命周期不一致问题,java只能拷贝局部变量的副本到局部内部类,如下代码

    static class A {

        String name;

        public A(String name) {
            this.name = name;
        }

        @Override
        protected void finalize() throws Throwable {
            try {
                // TODO. release native resources here.
                Log.i("jc", "Is calling finalize");
            }finally {
                super.finalize();
            }
        }
    }

    private void testFinal() {
        final A a  = new A("a");
        int b = 1;
        Log.i("jc", "local a: " + a.toString());

        class Inner implements Runnable {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.i("jc", "Inner local A object: " + a.toString());
                System.gc();
            }
        }

        new Thread(new Inner()).start();
    }

考虑到类Inner的实例和局部变量a的生命周期不一致,因此在Inner里面使用的a其实是局部a的副本, 我用粗体标注下: a .

既然是副本,说明Inner_a 和 a 指向同一个对象。

log 如下:
证明指向同一对象

**

  • 那么问题来了为什么要用final修饰?

通过前面的说明我们知道尽管 a 和 a 名字相同指向同一对象,但实际上不是一个变量,因此假设我们在类的内部给 a 重新复制,像以下:

    private void testFinal() {
        A a  = new A("1"); // instance '1'
        int b = 1;
        Log.i("jc", "local a: " + a.toString());

        class Inner implements Runnable {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                Log.i("jc", "Inner local A object: " + a.toString()); // 打印 instance '1'

                a = new A("2"); // instance '2'

                Log.i("jc", "Inner local A object: " + a.toString()); // 打印 instance '2'

                System.gc();
            }
        }

        new Thread(new Inner()).start();

        try {
            Thread.sleep(20000); // 睡眠20 s 等 Inner 里面的 run 方法 修改 a 的值。
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Log.i("jc", "After Inner modify , local a: " + a.toString()); //  假设不用final修饰,这里打印的还是 instance '1', 为何不是 instance '2' ?  是不是很别扭,看起来不合理?????


    }

我们会理所当然的认为局部a和内部类a是同一个a(而且这是我们想看到的),而事实上由于生命周期的不一致,不可能做到它们就是同一个a,而是复制局部a的值到内部类a,这样它们就指向同一个对象了,加上名字还一样,所以我们会认为是它们就是同一个a。
为了效果更佳逼真,使用final修饰,这样内外a将一直指向同一个对象了,去除人为的给其中任何一个a重新赋值的可能性,避免我们很容易发现其实它们不是同一个a, 更重要的是 避免出现以上代码所说的那种尴尬


怎么证明内外不是同一个a?

来一起看看.class文件
局部内部类能访问非final类型局部变量?_第1张图片

你可能感兴趣的:(学习记录)