如下代码是有错误的:
private void createAProgressDialog() { // TODO Auto-generated method stub ProgressDialog progressDialog = ProgressDialog.show(this, "病毒入侵!", "正在入侵..."); new Thread(new Runnable() { public void run() { // TODO Auto-generated method stub try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } progressDialog.dismiss(); } }).start(); }
如果在progressDialog变量中再加入一个final关键字就不会编译时报错了。要说原因的话,我们先来考虑一下下面这个问题:
上面代码中,如果createAProgressDialog方法执行完毕之后,变量progressDialog的生命周期就结束了,而此时Thread对象的生命周期有可能还没有结束,那么在Thread的run方法中继续访问progressDialog变量就变成不可能了。在这里Java内部采用了复制的手段来解决这个问题,如果这个变量的值在编译期间可以确定,则编译器默认会在匿名内部类(局部内部类)的常量池中添加一个内容相等的字面量或直接将相应的字节码嵌入到执行字节码中。这样一来,匿名内部类使用的变量是另一个局部变量,只不过值和方法中局部变量的值相等,因此和方法中的局部变量完全独立开。但是新的问题又来了,既然在run方法中的变量progressDialog和createAProgressDialog方法中的那个变量不是同一个变量(只是值相同而已),那么如果在run方法中改变该变量的值,就会造成数据的不一致性,这样就达不到原本的意图和要求。为了解决这个问题,Java编译器就限定必须将变量限制为final变量,不允许对变量进行更改(对于引用类型的变量,是不允许指向新的对象),这样数据不一致性的问题就得以解决了。
这个错误在创建一个匿名监听器的时候,如果监听器实现的方法中有用到外部变量的时候,那么那个外部变量必须设置为final
但是如果这个变量是全局变量,那么就不用设置为final!!