Biến được truy cập trong lớp bên trong. Cần được tuyên bố cuối cùng


116

Vì vậy, tiêu đề đã nói lên tất cả. Tôi nhận được một lỗi biên dịch bên trong của tôi onClick.

Đây là mã.

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
Nếu bạn đang sử dụng Eclipse thì bạn có thể nhấn Ctrl-1 (Cmd-1 trên OS X) với lỗi được chọn để xem Sửa nhanh sẽ hiển thị cho bạn những gì cần phải thay đổi. Xem thêm ở đây: depth-first.com/articles/2008/01/11/...
Intrications

Câu trả lời:


130

Nếu bạn không muốn biến nó thành cuối cùng, bạn luôn có thể đặt nó thành một biến toàn cục.


1
@KevinZhao Các biến toàn cục có cuối cùng sau khi chúng được khởi chạy không?
the_prole

@the_prole Tôi nghĩ rằng bạn có thể sử dụng chính thức trong Java, nhưng tôi không chắc chắn nếu bạn có thể sử dụng nó khi xây dựng ứng dụng Android, vì vậy Googling nó có thể là một ý tưởng tốt :-)
Kevin Triệu

15
Nhìn lại, sử dụng các biến toàn cục là một ý tưởng tồi nếu bạn có thể tránh được chúng, trừ khi bạn là người mới bắt đầu, trong trường hợp đó, việc phức tạp hóa chương trình của bạn với các biến toàn cầu là một kinh nghiệm học tập tốt. Đây là một bài viết hay giải thích tại sao biến toàn cục là một ý tưởng tồi.
the_prole

65

Bạn có thể khai báo biến cuối cùng hoặc biến nó thành một biến thể hiện (hoặc toàn cục). Nếu bạn tuyên bố nó là cuối cùng, bạn sẽ không thể thay đổi nó sau này.

Bất kỳ biến nào được xác định trong một phương thức và được truy cập bởi một lớp bên trong ẩn danh phải là biến cuối cùng. Nếu không, bạn có thể sử dụng biến đó trong lớp bên trong mà không biết rằng nếu biến thay đổi trong lớp bên trong và sau đó nó được sử dụng sau đó trong phạm vi bao quanh, thì những thay đổi được thực hiện trong lớp bên trong sẽ không tồn tại trong phạm vi bao. Về cơ bản, những gì xảy ra trong lớp bên trong vẫn nằm trong lớp bên trong.

Tôi đã viết một lời giải thích sâu hơn ở đây . Nó cũng giải thích tại sao các biến instance và global không cần phải được khai báo cuối cùng.


44

Lỗi nói lên tất cả, hãy thay đổi:

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

đến

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

87
Lý do: nếu hai phương thức thấy cùng một biến cục bộ, Java muốn bạn thề rằng bạn sẽ không thay đổi nó - final, trong Java nói. Cùng với sự vắng mặt của các tham số tham chiếu, quy tắc này đảm bảo rằng các local chỉ được gán trong phương thức mà chúng thuộc về. Mã do đó dễ đọc hơn.
ignis

@ignis Tôi đang gặp lỗi NullPointerException, addSiteButton.setOnClickListener(new View.OnClickListener() {bạn có biết tại sao điều đó lại xảy ra không?
PhDeOliveira

1
@PhDeOliveira NPE thường được ném khi bạn gọi một phương thức trên một biến có chứa null. Có thể, findViewById đang trở lại null. Tôi không thể nói nhiều hơn, không phải là một lập trình viên Android; Tôi khuyên bạn nên mở một câu hỏi riêng. Chắc chắn, nó không liên quan gì đến các lớp bên trong, cuối cùng, et similia .
ignis

25

Đây là một câu trả lời hài hước.

Bạn có thể khai báo mảng một phần tử cuối cùng và thay đổi các phần tử của mảng mà bạn muốn. Tôi chắc chắn rằng nó phá vỡ chính lý do tại sao quy tắc trình biên dịch này được triển khai ngay từ đầu nhưng nó rất hữu ích khi bạn đang ở trong tình trạng ràng buộc thời gian như tôi hiện nay.

Tôi thực sự không thể yêu cầu tín dụng cho cái này. Đó là khuyến nghị của IntelliJ! Cảm thấy hơi khó hiểu. Nhưng có vẻ không tệ như một biến toàn cục nên tôi nghĩ nó đáng nói ở đây. Đó chỉ là một giải pháp cho vấn đề. Không nhất thiết phải là tốt nhất.

final int[] tapCount = {0};

addSiteButton.setOnClickListener(new View.OnClickListener() {

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

});

Trong trường hợp trên, bạn không thay đổi đối tượng được tham chiếu mà thay đổi nội dung bên trong mảng. liên kết có lời giải thích tốt đẹp.
Abilash

Vâng tôi biết. Có vẻ như đây chỉ là một vụ hack để giải quyết vấn đề. Cảm ơn bình luận của bạn đã làm sáng tỏ nó cho những người khác.
the_new_mr

4

Như @Veger đã nói, bạn có thể tạo nó finalđể biến có thể được sử dụng trong lớp bên trong.

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

Tôi đã gọi nó pagerhơn là mPagervì bạn đang sử dụng nó như một biến cục bộ trong onCreatephương thức. Cácm tiền tố cusomarily dành cho các biến thành viên lớp (tức là các biến được khai báo ở đầu của lớp và có sẵn cho tất cả các phương pháp lớp).

Nếu bạn thực sự cần một biến thành viên của lớp, thì việc biến nó thành cuối cùng sẽ không hiệu quả vì bạn không thể sử dụng findViewByIdđể đặt giá trị của nó cho đến khi onCreate. Giải pháp là không sử dụng một lớp bên trong ẩn danh. Bằng cách này, mPagerbiến không cần khai báo cuối cùng và có thể được sử dụng trong toàn bộ lớp.

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();
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.