【问题标题】:Cannot refer to a non-final variable i inside an inner class defined in a different method不能在不同方法中定义的内部类中引用非最终变量 i
【发布时间】:2011-05-13 21:27:23
【问题描述】:

我有“无法在以不同方法定义的内部类中引用非最终变量 i”错误...我哪里出错了?...我刚开始学习 android 和 java 编程..

public class Tictac extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

        Button button[] = new Button[9];
        button[0]= (Button) findViewById(R.id.button1);
        button[1] = (Button) findViewById(R.id.button2);
        button[2] = (Button) findViewById(R.id.button3);
        button[3] = (Button) findViewById(R.id.button4);
        button[4] = (Button) findViewById(R.id.button5);
        button[5] = (Button) findViewById(R.id.button6);
        button[6] = (Button) findViewById(R.id.button7);
        button[7] = (Button) findViewById(R.id.button8);
        button[8] = (Button) findViewById(R.id.button9);


        final TextView text = (TextView) findViewById(R.id.textView1);

        final ImageView img[] = new ImageView[9];
        img[0] = (ImageView) findViewById(R.id.img1);
        img[1] = (ImageView) findViewById(R.id.img2);
        img[2] = (ImageView) findViewById(R.id.img3);
        img[3] = (ImageView) findViewById(R.id.img4);
        img[4] = (ImageView) findViewById(R.id.img5);
        img[5] = (ImageView) findViewById(R.id.img6);
        img[6] = (ImageView) findViewById(R.id.img7);
        img[7] = (ImageView) findViewById(R.id.img8);
        img[8] = (ImageView) findViewById(R.id.img9);
        final ImageView imSq[] = new ImageView[9];
        imSq[0] = (ImageView) findViewById(R.id.imSq1);
        imSq[1] = (ImageView) findViewById(R.id.imSq2);
        imSq[2] = (ImageView) findViewById(R.id.imSq3);
        imSq[3] = (ImageView) findViewById(R.id.imSq4);
        imSq[4] = (ImageView) findViewById(R.id.imSq5);
        imSq[5] = (ImageView) findViewById(R.id.imSq6);
        imSq[6] = (ImageView) findViewById(R.id.imSq7);
        imSq[7] = (ImageView) findViewById(R.id.imSq8);
        imSq[8] = (ImageView) findViewById(R.id.imSq9);


        for(int i =0;i <=8;i++){
        if(i%2==0){
             button[i].setOnClickListener(new View.OnClickListener() {
                     public void onClick(View v) {
        **HERE-->**       img[i].setVisibility(2);
                         text.setText("COOL");

                    }
                    });
        }
        else{   
             button[i].setOnClickListener(new View.OnClickListener() {
                     public void onClick(View v) {
         **HERE-->**        imSq[i].setVisibility(2);
                         text.setText("COOL");

                    }
                    });
    }



        }

}      

}

【问题讨论】:

  • 问题是:虽然你的数组是最终的,但这些数组的元素不是最终的。
  • @Cephron:不,这根本不是问题。
  • 当有人点击你的按钮时,'i'的值是多少?

标签: java android


【解决方案1】:

错误消息准确地说明了问题所在:i 变量不是最终变量,但您正试图在匿名内部类中引用它。

你可以这样做:

for (int i = 0; i <= 8;i++) {
  if (i % 2 == 0) {
     final int j = i;
     button[i].setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
           img[j].setVisibility(2);
           text.setText("COOL");
         }
     });
  }
}

这里我们获取变量i副本,并将其分配给最终变量j,然后我们可以在匿名内部类中使用它。或者,如果您不关心数组更改的可能性,您可以这样做:

for (int i = 0; i <= 8;i++) {
  if (i % 2 == 0) {
     final ImageView imageView = img[i];
     button[i].setOnClickListener(new View.OnClickListener() {
         public void onClick(View v) {
           imageView.setVisibility(2);
           text.setText("COOL");
         }
     });
  }
}

来自section 8.1.3 of the Java Language Specification

任何使用但未在内部类中声明的局部变量、形式方法参数或异常处理程序参数都必须声明为 final。任何在内部类中使用但未声明的局部变量必须在内部类的主体之前明确分配(第 16 节)。

【讨论】:

  • 好的.. 谢谢:).. 这不是我想做的.. 但你的建议奏效了.. 再次感谢
  • 为什么在内部类中使用但未声明的局部变量、形式方法参数或异常处理程序参数必须声明为final?
  • @Roberto:这是因为该值被有效地传递给了匿名内部类的编译器生成的构造函数。通过使变量成为最终变量,您可以避免在内部类中读取“已更改”变量并期望看到新值,而实际上您只会看到旧值。
【解决方案2】:

你可以创建一个方法,像这样:

private void method(final Button btn, final ImageView img) {
    btn.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            img.setVisibility(2);
            text.setText("COOL");
        }
    });
}

并在你的 for i 循环中使用它。 这应该可以工作(未经测试)

【讨论】:

    猜你喜欢
    • 2010-11-20
    • 2014-12-09
    • 2012-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多