关于final大家都知道,网上一搜一大片,大体说的都是final的意思就是保证我们所定义的变量的值不可改变或者引用不可改变~~
总所周知,在java匿名类中我们要去使用外部的局部变量或者参数是,这个被匿名类使用的变量必须是final的,但是大家有没有想过为什么必须是final,总不能说他是final我们就写final好了,这做法白痴都会,接下来我们来讲解下其内部原因。
在介绍之前我们首先要讲解下java中的值传递和引用传递的问题,大家都知道java是值传递,例
public class Test {
public static void main(String[] args) {
String s ="out";
test1(s);
System.out.println(s);
}
public static void test1(String s){
s = "inner";
}
}
打印结果是:"out",这也就是java值传递导致的原因,简单分析下吧,在我们讲s变量传递到test1方法中去的时候,实际上是在栈上copy了一份s的引用,然后操作这个引用,当s重新赋值的时候地址就改变(String是不可变的嘛),完全没有影响到原先s的内容。
介绍了java值传递后,接下来我们来说回归正题,如下面这段代码:
//定义个抽象类
abstract class AbstractClass{
public abstract void m();
}
public static void test(final String s){
AbstractClass c = new AbstractClass(){
public void m(){
s = "inner";
System.out.println(s);
}
};
}
实际上这段代码是被编译成:
public static void test(final String s){
class OuterClass$1 extends AbstractClass{
private final String s;
public OuterClass$1(String s){
this.s = s;
}
public void m(){
s = "inner";
System.out.println(s);
}
};
AbstractClassc = new OuterClass$1(s);
}
可以看到s对象是被传递到了构造函数当中,当我们在使用m来打印出来,但如果java可以让我们以非final类型的参数传递进去的话。由java值传递可知,我们在匿名类中修改该变量的值,那在外部是不可见的。
举个最常见的例子,大家都写过button,我们为他添加匿名类事件监听器,如果我们在内部里面修改了外部变量的引用,那我们在外面是获取不到修改了的值的,这个可以接受?这也就是上面我们所举的值传递的例子。
所以结论出来了,我们在匿名类中需要传递进来final关键字,java希望的是保证内部实现和外在表现的一致性。
ok。。写完了自己的一些看法。一些内容参考部分内容参见