为什么编译器在内部类中接受非final变量?

3

我正在创建一个带有进度条的MediaPlayer。在这里,mp是一个MediaPlayer对象,而seeker是在MainActivity类中创建的一个seekbar对象。

我的理解是,只有final成员才能被匿名内部类访问。那么runnable如何访问那些对象(mp和seeker)呢?

     h = new Handler();  // create a handler for the MainActivity

 //create a runnable activity to change the progress of seekbar in MainThread for every 1 sec
   Runnable r = new Runnable() {
        @Override
        public void run() {
            if (mp != null) {
                seeker.setProgress(mp.getCurrentPosition() / 1000);
            }
           h.postDelayed(this, 1000);
        }
   };

    this.runOnUiThread(r);

注意:代码运行完美。感谢帮助。

1
@user3215142...有一个规则,这些变量必须是“final”,这才是问题的实质。你声称“推荐的方法是使你的runnables静态”的说法需要证实。 - user207421
1个回答

4

这是因为存在一种叫做有效最终(effectively final)的概念。

jls-8.1.3:

任何在内部类中使用但没有声明的局部变量、形式参数或异常参数必须声明为final或有效最终(§4.12.4),否则编译时会在尝试使用时出现错误。

jls-4.12.4:

如果一个变量是有效最终的,则在其声明中添加final修饰符不会引入任何编译时错误。相反,如果在有效程序中某个局部变量或参数被声明为final,则如果删除final修饰符,则该变量将变成有效最终。

当变量只设置了一次并且在内部类中使用时,编译器将变量的修饰符转换为final

考虑以下代码Tests.java:

public class Tests  {
   public static void main(String[] args) throws Throwable {
       String value = "Hello";

       Runnable runnable = new Runnable() {
           @Override
           public void run() {
               System.out.println(value);
           }
       };
   }
}

编译上面的代码将生成以下代码。你能看到编译器把 value 的修饰符改变成了 final 吗?

Tests.class (反编译):

public class Tests {
    public Tests() {
    }

    public static void main(String[] args) throws Throwable {
        final String value = "Hello";
        Runnable var10000 = new Runnable() {
            public void run() {
                System.out.println(value);
            }
        };
    }
}

但是,如果你改变变量的值(见下面的代码),它将无法编译,因为编译器知道它不是一个有效的final变量:

public class Tests  {
   public static void main(String[] args) throws Throwable {
       String value = "Hello";
       value = "world";

       Runnable runnable = new Runnable() {
           @Override
           public void run() {
               System.out.println(value);
           }
       };
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接