Java中为什么内部类对外部类局部变量有引用时,外部类局部变量一定要有final?

Java中为什么内部类对外部类局部变量有引用时,外部类局部变量一定要有final?
 
我们来看看Java对内部类的实现。
使用内部类经常是用在Listener这样的。而Listener中的监听函数被调用时,大部分情况,new内部类所在的函数早就执行完了,此时外部类局部变量(保存在栈中)早就因为函数的退出而失效了。
 
而加上final后,编译器是这样处理内部类的。 如果这个外部局部变量是常量,则在内部类代码中直接用这个常量。如果是类的实例,则编译器将产生一个内部类的构造参数,将这个final变量传到内部类里,这样即使外部局部变量无效了,还可以使用。
 
例如:
01    import java.util.*;
02  
03public class Test{
04    public void run() {
05        final List a=new ArrayList();
06        class B{
07            public int c;
08            public void run(){
09                List b;
10                b=a;
11                System.out.println(b);
12            }
13        };
14  
15        B b=new B();
16  
17        b.c=0;
18    }
19}
 
使用javap -private Test$1B(这个就是内部类)将看到
Compiled from "Test.java"
class Test$1B extends java.lang.Object{
    public int c;
    private final java.util.List val$a;
    private final Test this$0;
    Test$1B(Test,java.util.List);
    public void run();
}
 
而下面是使用常量的例子:
01    public class Test{
02    public void run() {
03        final int a=100;
04        class B{
05            public int c;
06            public void run(){
07                int b;
08                b=a;
09                System.out.println(b);
10            }
11        };
12  
13        B b=new B();
14  
15        b.c=0;
16    }
17}
 
javap -private -c Test$1B:
 
Compiled from "Test.java"
class Test$1B extends java.lang.Object{
public int c;
 
private final Test this$0;
 
Test$1B(Test);
Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   aload_1
   6:   putfield        #2; //Field this$0:LTest;
   9:   return
 
public void run();
Code:
   0:   bipush 100
   2:   istore_1
   3:   getstatic       #3; //Field java/lang/System.out:Ljava/io/PrintStream;
   6:   iload_1
   7:   invokevirtual   #4; //Method java/io/PrintStream.println:(I)V
   10: return
 
}
 
另外引用别人的一段话:
 
内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,自己内部的方法调用的实际是自己的属性而不是外部类方法的参数。 
 
这样理解就很容易得出为什么要用final了,因为两者从外表看起来是同一个东西,实际上却不是这样,如果内部类改掉了这些参数的值也不可能影响到原参数,然而这样却失去了参数的一致性,因为从编程人员的角度来看他们是同一个东西。
 
如果我们不强制使用final的话,那么编程人员在程序设计的时候在内部类中改掉参数的值,但是外部调用的时候又发现值其实没有被改掉,这就让人非常的难以理解和接受,为了避免这种尴尬的问题存在,所以编译器设计人员把内部类能够使用的参数设定为必须是final来规避这种莫名其妙错误的存在。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值