内部类访问局部变量的时候,为什么变量必须加上final修饰

519 查看

这里的局部变量就是在类方法中的变量,能访问方法中变量的类当然也是局部内部类了。
我们都知道,局部变量在所处的函数执行完之后就释放了,但是内部类对象如果还有引用指向的话它是还存在的。例如下面的代码:

class Outer{                                                                       
        public static void main(String[] args){
                Outer out = new Outer();
                Object obj = out.method();
        }   

        Object method(){
                int locvar = 1;
                class Inner{
                        void displayLocvar(){
                                System.out.println("locvar = " + locvar);
                        }
                }
                Object in = new Inner();
                return in; 
        }
}

当out.method()方法执行结束后,局部变量 locvar 就消失了,但是在method()方法中 obj in = new Inner() 产生的 in 对象还存在引用obj,这样对象就访问了一个不存在的变量,是不允许的。这种矛盾是由局部内部类可以访问局部变量但是局部内部类对象和局部变量的生命周期不同而引起的。

局部内部类访问局部变量的机制

在java中,类是封装的,内部类也不例外。我们知道,非静态内部类能够访问外部类成员是因为它持有外部类对象的引用 Outer.this, 就像子类对像能够访问父类成员是持有父类对象引用super一样。局部内部类也和一般内部类一样,只持有了Outer.this,能够访问外部类成员,但是它又是如何访问到局部变量的呢?

实际上java是将局部变量作为参数传给了局部内部类的构造函数,而将其作为内部类的成员属性封装在了类中。我们看到的内部类访问局部变量实际上只是访问了自己的成员属性而已,这和类的封装性是一致的。那么上面的代码实际上是这样:

Object method(){
                int locvar = 1;
                class Inner{
                    private int obj;
                    public Inner(int obj){
                        this.obj = obj;
                    }
                        void displayLocvar(){
                                System.out.println("locvar = " + locvar);
                        }
                }
                Object in = new Inner(locvar);  //将locvar作为参数传给构造,以初始话成员
                return in; 
        }

那么问题又来了,我们写代码的目的是在内部类中直接控制局部变量和引用,但是java这么整我们就不高兴了,我在内部类中整半天想着是在操作外部变量,结果你给整个副本给我,我搞半天丫是整我自己的东西啊?要是java不这么整吧,由破坏了封装性--------你个局部内部类牛啊,啥都没有还能看局部变量呢。这不是java风格,肯定不能这么干。这咋整呢?
想想,类的封装性咱们一定是要遵守的,不能破坏大局啊。但又要保证两个东西是一模一样的,包括对象和普通变量,那就使用final嘛,当传递普通变量的之前我把它变成一个常量给你,当传递引用对象的时候加上final就声明了这个引用就只能指着这一个对象了。这样就保证了内外统一。