在不同方法中定义的内部类中无法引用非 final 变量 i。

4

我遇到了“在不同方法中定义的内部类中无法引用非最终变量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");

                    }
                    });
    }



        }

}      

}


问题在于:虽然您的数组是final的,但这些数组的元素并不是final的。 - Cephron
1
@Cephron:不,那根本不是问题所在。 - Jon Skeet
当有人点击您的按钮时,“i”的值将是什么? - James
2个回答

11

错误消息清楚地指出了问题:变量 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");
         }
     });
  }
}

根据Java语言规范第8.1.3节

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


好的..谢谢 :)..虽然这不是我想做的..但你的建议起作用了..所以再次感谢 - Sergio
为什么在内部类中使用但未声明的任何局部变量、形式方法参数或异常处理程序参数都必须声明为final? - Roberto
2
@Roberto:这是因为值实际上被传递给匿名内部类的编译器生成的构造函数。通过将变量设置为final,可以避免在内部类中读取“更改”的变量并期望看到新的值的情况,而实际上只会看到旧值。 - Jon Skeet

0
你可以创建一个方法,就像这样:
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循环中使用它。 这应该可以工作(未经测试)


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