ตัวแปรสามารถเข้าถึงได้ภายในคลาสภายใน จำเป็นต้องประกาศให้เป็นที่สิ้นสุด


116

ดังนั้นชื่อจึงบอกทุกอย่าง ฉันได้รับข้อผิดพลาดในการคอมไพล์ภายใน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 (Cmd-1 บน OS X) โดยเลือกข้อผิดพลาดเพื่อดู Quick Fix ซึ่งจะแสดงสิ่งที่จำเป็นต้องเปลี่ยนแปลง ดูเพิ่มเติมได้ที่นี่: depth-first.com/articles/2008/01/11/...
Intrications

คำตอบ:


130

หากคุณไม่ต้องการทำให้มันจบลงคุณสามารถทำให้มันเป็นตัวแปรส่วนกลางได้ตลอดเวลา


1
@KevinZhao ตัวแปรส่วนกลางจะสิ้นสุดเมื่อเริ่มต้นแล้วหรือไม่?
the_prole

@the_prole ฉันคิดว่าคุณสามารถใช้ขั้นสุดท้ายใน Java ได้ แต่ฉันไม่แน่ใจว่าคุณสามารถใช้มันได้หรือไม่เมื่อสร้างแอพ Android ดังนั้น Googling มันอาจจะเป็นความคิดที่ดี :-)
Kevin Zhao

15
หากมองย้อนกลับไปการใช้ตัวแปรส่วนกลางเป็นความคิดที่ไม่ดีหากสามารถหลีกเลี่ยงได้เว้นแต่คุณจะเป็นผู้เริ่มต้นซึ่งในกรณีนี้การทำให้โปรแกรมของคุณซับซ้อนเกินไปกับโลกจะเป็นประสบการณ์การเรียนรู้ที่ดี นี่คือบทความดีๆที่อธิบายว่าทำไมตัวแปรทั่วโลกจึงเป็นความคิดที่ไม่ดี
the_prole

65

คุณสามารถประกาศตัวแปรสุดท้ายหรือทำให้เป็นตัวแปรอินสแตนซ์ (หรือโกลบอล) หากคุณประกาศเป็นที่สิ้นสุดคุณจะไม่สามารถเปลี่ยนแปลงได้ในภายหลัง

ตัวแปรใด ๆ ที่กำหนดในวิธีการและเข้าถึงโดยคลาสภายในที่ไม่ระบุชื่อจะต้องเป็นขั้นสุดท้าย มิฉะนั้นคุณสามารถใช้ตัวแปรนั้นในคลาสภายในโดยไม่ทราบว่าหากตัวแปรเปลี่ยนแปลงในคลาสภายในและจากนั้นจะถูกใช้ในขอบเขตการปิดในภายหลังการเปลี่ยนแปลงที่ทำในคลาสภายในจะไม่คงอยู่ในขอบเขตการปิดล้อม โดยพื้นฐานแล้วสิ่งที่เกิดขึ้นในชั้นในจะอยู่ในชั้นใน

ผมเขียนขึ้นคำอธิบายในเชิงลึกที่นี่ นอกจากนี้ยังอธิบายว่าเหตุใดอินสแตนซ์และตัวแปรส่วนกลางจึงไม่จำเป็นต้องประกาศขั้นสุดท้าย


44

ข้อผิดพลาดบอกว่าทั้งหมดเปลี่ยน:

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

ถึง

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

87
เหตุผล: หากสองวิธีเห็นตัวแปรท้องถิ่นเดียวกัน Java ต้องการให้คุณสาบานว่าคุณจะไม่เปลี่ยนแปลง - finalในภาษา Java ร่วมกับการไม่มีพารามิเตอร์อ้างอิงกฎนี้ช่วยให้มั่นใจได้ว่าชาวบ้านจะถูกกำหนดเฉพาะในวิธีการที่พวกเขาเป็นเจ้าของเท่านั้น โค้ดจึงอ่านได้ง่ายขึ้น
ignis

@ignis ฉันได้รับข้อผิดพลาด NullPointerException addSiteButton.setOnClickListener(new View.OnClickListener() {คุณมีความคิดว่าทำไมจึงเกิดขึ้น
PhDeOliveira

1
โดยทั่วไป @PhDeOliveira NPE จะถูกโยนทิ้งเมื่อคุณเรียกใช้เมธอดในตัวแปรที่มีnullไฟล์. อาจfindViewByIdnullจะกลับมา ฉันไม่สามารถพูดได้มากกว่านี้ไม่ใช่โปรแกรมเมอร์ Android ฉันแนะนำให้คุณเปิดคำถามแยกต่างหาก แน่นอนมันมีอะไรจะทำอย่างไรกับการเรียนภายในสุดท้าย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นี้ไม่จำเป็นต้องประกาศตัวแปรขั้นสุดท้ายและสามารถใช้ได้ตลอดทั้งคลาส

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.