변수는 내부 클래스 내에서 액세스됩니다. 최종 선언 필요


116

그래서 제목은 모든 것을 말합니다. 내 .NET 내부에서 컴파일 오류가 발생 onClick합니다.

여기에 코드가 있습니다.

public class fieldsActivity extends Activity {

Button addSiteButton;
Button cancelButton;
Button signInButton;


/**
 * Called when the activity is first created.
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // to create a custom title bar for activity window
    requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);

    setContentView(R.layout.fields);
    // use custom layout title bar
    getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.topbar);

    Pager adapter = new Pager();
    ViewPager mPager = (ViewPager) findViewById(R.id.fieldspager);
    mPager.setAdapter(adapter);
    mPager.setCurrentItem(1);



    addSiteButton = (Button) findViewById(R.id.addSiteButton);
    addSiteButton.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
           mPager.setCurrentItem(2, true); //Compilation error happens here.
        }


    });


    cancelButton = (Button) findViewById(R.id.cancel_button);
    signInButton = (Button) findViewById(R.id.sign_in_button);

}

1
Eclipse를 사용하는 경우 오류를 선택한 상태에서 Ctrl-1 (OS X의 경우 Cmd-1)을 눌러 변경해야 할 사항을 보여주는 빠른 수정을 볼 수 있습니다. 여기에서 더보기 : depth-first.com/articles/2008/01/11/…
Intrications

답변:


130

최종적으로 만들고 싶지 않다면 항상 전역 변수로 만들 수 있습니다.


1
@KevinZhao 초기화 된 전역 변수는 최종입니까?
the_prole

@the_prole 난 당신이 자바에서 최종 사용할 수 있습니다 생각하지만, 나는 확실하지 않다 그것은 좋은 아이디어 :-) 수 있습니다 인터넷 검색, 그래서 안드로이드 응용 프로그램을 구축 할 때 당신은 그것을 사용할 수 있는지
케빈 자오

15
돌이켜 보면, 초보자가 아니라면 피할 수 있다면 전역 변수를 사용하는 것은 좋지 않은 생각입니다.이 경우 프로그램을 전역으로 지나치게 복잡하게 만드는 것은 좋은 학습 경험입니다. 여기에 전역 변수 나쁜 생각입니다 이유를 설명하는 좋은 기사입니다.
the_prole nov.

65

변수를 final로 선언하거나 인스턴스 (또는 전역) 변수로 만들 수 있습니다. 최종적으로 선언하면 나중에 변경할 수 없습니다.

메서드에 정의되고 익명 내부 클래스에서 액세스하는 모든 변수는 최종 변수 여야합니다. 그렇지 않으면 내부 클래스에서 해당 변수를 사용할 수 있습니다. 변수가 내부 클래스에서 변경된 다음 나중에 엔 클로징 범위에서 사용되는 경우 내부 클래스에서 변경된 내용이 엔 클로징 범위에서 유지되지 않는다는 사실을 알지 못합니다. 기본적으로 내부 클래스에서 일어나는 일은 내부 클래스에 남아 있습니다.

여기에 더 자세한 설명을 썼습니다 . 또한 인스턴스 및 전역 변수를 final로 선언 할 필요가없는 이유도 설명합니다.


44

오류는 모든 것을 말합니다.

ViewPager mPager = (ViewPager) findViewById(R.id.fieldspager);

final ViewPager mPager = (ViewPager) findViewById(R.id.fieldspager);

87
이유 : 두 메서드가 동일한 로컬 변수를 볼 경우 Java는 변경하지 않겠다고 맹세하기를 원합니다 final. 참조 기준 매개 변수의 부재와 함께이 규칙은 로컬이 속한 메소드에만 할당되도록합니다. 따라서 코드를 더 쉽게 읽을 수 있습니다.
2013 년

@ignis NullPointerException 오류가 발생합니다. addSiteButton.setOnClickListener(new View.OnClickListener() {왜 그런 일이 발생하는지 알 수 있습니까?
PhDeOliveira

1
@PhDeOliveira NPE는 일반적으로를 포함하는 변수에서 메서드를 호출 할 때 발생합니다 null. 아마도 findViewByIdnull. 더 이상 말할 수는 없습니다. Android 프로그래머가 아닙니다. 별도의 질문을 여는 것이 좋습니다. 확실히, 그것은 내부 클래스, final, et similia 와는 아무 관련이 없습니다 .
ignis

25

재미있는 대답이 있습니다.

최종 단일 요소 배열을 선언하고 배열의 요소를 원하는대로 변경할 수 있습니다. 이 컴파일러 규칙이 처음에 구현 된 바로 그 이유를 깨뜨릴 것이라고 확신하지만, 오늘처럼 타임 바인드에있을 때 편리합니다.

나는 실제로 이것에 대한 크레딧을 청구 할 수 없습니다. IntelliJ의 추천이었습니다! 약간 엉뚱한 느낌입니다. 그러나 전역 변수만큼 나쁘지는 않아서 여기서 언급 할 가치가 있다고 생각했습니다. 문제에 대한 하나의 해결책 일뿐입니다. 반드시 최고의 것은 아닙니다.

final int[] tapCount = {0};

addSiteButton.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
       tapCount[0]++;
    }

});

위의 경우 참조 된 객체를 변경하지 않고 배열 내부의 내용을 변경합니다. 링크 에 좋은 설명이 있습니다.
Abilash

네, 알아요. 문제를 해결하는 해킹처럼 보입니다. 다른 사람들을 위해 설명 해주셔서 감사합니다.
the_new_mr

4

@Veger가 말했듯 final이 변수를 내부 클래스에서 사용할 수 있도록 만들 수 있습니다.

final ViewPager pager = (ViewPager) findViewById(R.id.fieldspager);

나는 그것을라는 pager것이 아니라 mPager당신이에서 로컬 변수로 사용하고 있기 때문에 onCreate방법. m접두사는 cusomarily 클래스 멤버 변수 (클래스의 시작 부분에 선언 된 모든 클래스 메소드에 사용할 수 있습니다 즉, 변수를) 예약되어 있습니다.

당신이 실제로 클래스 멤버 변수를해야하는 경우, 그것은 최종 사용자가 사용할 수 없기 때문에 할 작동하지 않습니다 findViewById때까지 값을 설정합니다 onCreate. 해결책은 익명의 내부 클래스를 사용하지 않는 것입니다. 이렇게하면 mPager변수를 final로 선언 할 필요가 없으며 클래스 전체에서 사용할 수 있습니다.

public class MainActivity extends AppCompatActivity {

    private ViewPager mPager;
    private Button mButton;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // ...

        mPager = (ViewPager) findViewById(R.id.fieldspager);

        // ...

        mButton.setOnClickListener(myButtonClickHandler);
    }


    View.OnClickListener myButtonClickHandler = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mPager.setCurrentItem(2, true);
        }
    };
}

0
    public class ConfigureActivity extends Activity {

        EditText etOne;
        EditText etTwo;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_configure);

            Button btnConfigure = findViewById(R.id.btnConfigure1);   
            btnConfigure.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            configure();
                        }
                    });
    }

    public  void configure(){
            String one = etOne.getText().toString();
            String two = etTwo.getText().toString();
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.