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

时间:2016-10-30 03:42:18

标签: java android compiler-errors

我正在创建一个带有seekbar的MediaPlayer.Here, mp 是一个MediaPlayer对象,而 seeker 是在MainActivity类中创建的搜索栏对象。

我的理解是,只有最终成员才能访问匿名内部类。然后 runnable如何访问这些对象(mp和搜索者)。

     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 个答案:

答案 0 :(得分:4)

它发生了,因为有一种叫做有效的最终

<强> jls-8.1.3:

  

在内部类中使用但未声明的任何局部变量,形式参数或异常参数必须声明为final或者是有效的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);
            }
        };
    }
}

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

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);
           }
       };
   }
}