2012년 11월 22일 목요일

지역변수에 final이 붙을 때의 의미에 대해(Cannot refer to a non-final variable 문제)





지역변수에 final이 붙을 때의 의미에 대해

만일 아래 코드에서 mText에 final이 붙지 않은 상태에서  
layout.setOnTouchListener()에서 mText를 사용하고자 하면
컴파일 단계에서 아래와 같은 에러가 발생한다.

Cannot refer to a non-final variable mText inside an inner class defined in a different method

이유가 뭘까? 같은 onCreate() 메소드 안에 있는 변수인데...?
그 이유는...

public class AAAActivity extends Activity  {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        final TextView mText = (TextView)findViewById(R.id.textV);
        
        LinearLayout layout = (LinearLayout)findViewById(R.id.linear);
        layout.setOnTouchListener(new View.OnTouchListener() {
          public boolean onTouch(View v, MotionEvent e) {
              mText.setText("Touched"); //에러 발생
                return true;
          }
        });
    }


  • mText는 전역변수도 아니고, onTouch()의 지역 변수도 아니며 onCreate()의 지역 변수로 선언되어 있다.
  • 리스너인 onTouch()는 onCreate()에 속한 지역 메서드가 아니라는 점을 주의해야 한다. onCreate()가 실행시에 onTouch()가 같이 실행되는 것이 아니라 터치 이벤트 발생시 실행할 메스드로 등록만 할 뿐이다.
  • 에러가 발생하는 이유는 mText 변수는 onCreate()가 리턴되면 사라지는 지역 변수이다.  반면 onTouch()는 터치 리스너로 등록되며 onCreate()가  리턴된 후에라도 이벤트가 발생하면 언제든지 호출될 수 있다. onTouch()가 호출되었을 때는 mText 변수가 존재하지 않으므로 mText의 실제값을 참조할 길이 없다. 미래에 호출될 리스너에게 현재의 지역 변수값을 전달하는 것은 불가능하다.
  • 그런데 여기서 지역 변수에 final을 붙이면 더 이상 변경할 수 없는 상수가 되므로 onTouch()를 등록하는 시점에 그 값을 분명히 전달할 수 있다. 

댓글 없음:

댓글 쓰기