ไม่สามารถทำการอ้างอิงแบบคงที่กับวิธีการไม่คงที่


102

การสร้างแอปพลิเคชันหลายภาษาใน Java รับข้อผิดพลาดเมื่อแทรกค่าสตริงจากR.stringไฟล์ XML ของทรัพยากร:

public static final String TTT =  (String) getText(R.string.TTT);

นี่คือข้อความแสดงข้อผิดพลาด:

ข้อผิดพลาด: ไม่สามารถทำการอ้างอิงแบบคงที่ไปยังวิธีการที่ไม่คงที่ getText (int) จากประเภทบริบท

เกิดจากสาเหตุใดและจะแก้ได้อย่างไร?


1
ทำไมคุณถึงต้องใช้มันเป็นแบบคงที่สำหรับ 'แอปพลิเคชันหลายภาษา' ไม่เข้าใจจริงๆ.
xil3

3
อย่าเก็บทรัพยากรสตริงในสมาชิกข้อมูลคงที่ ขอได้เสมอgetString()เมื่อคุณต้องการ ด้วยวิธีนี้แอปพลิเคชันของคุณจะปรับให้เหมาะสมกับผู้ใช้ที่เปลี่ยนภาษาที่ตนเลือก
CommonsWare

คำตอบ:


143

เนื่องจากgetText()ไม่คงที่คุณจึงไม่สามารถเรียกใช้จากวิธีคงที่ได้

เพื่อให้เข้าใจว่าทำไมคุณต้องเข้าใจความแตกต่างระหว่างทั้งสอง

วิธีการอินสแตนซ์ (ไม่คงที่) ใช้กับอ็อบเจ็กต์ที่เป็นประเภทเฉพาะ (คลาส) สิ่งเหล่านี้ถูกสร้างขึ้นด้วยสิ่งใหม่เช่นนี้:

SomeClass myObject = new SomeClass();

ในการเรียกวิธีการอินสแตนซ์คุณเรียกมันบนอินสแตนซ์ ( myObject):

myObject.getText(...)

อย่างไรก็ตามเมธอด / ฟิลด์แบบคงที่สามารถเรียกได้เฉพาะในประเภทโดยตรงพูดเช่นนี้: คำสั่งก่อนหน้านี้ไม่ถูกต้อง นอกจากนี้ยังสามารถอ้างถึงฟิลด์แบบคงที่ด้วยการอ้างอิงอ็อบเจ็กต์เช่น myObject.staticMethod()นี้ แต่ไม่ควรใช้เพราะไม่ได้ระบุให้ชัดเจนว่าเป็นตัวแปรคลาส

... = SomeClass.final

และทั้งสองไม่สามารถทำงานร่วมกันได้เนื่องจากทำงานบนพื้นที่ข้อมูลที่แตกต่างกัน (ข้อมูลอินสแตนซ์และข้อมูลคลาส)

ให้ฉันลองอธิบาย พิจารณาคลาสนี้ (psuedocode):

class Test {
     string somedata = "99";
     string getText() { return somedata; } 
     static string TTT = "0";
}

ตอนนี้ฉันมีกรณีการใช้งานต่อไปนี้:

Test item1 = new Test();
 item1.somedata = "200";

 Test item2 = new Test();

 Test.TTT = "1";

มีค่าอะไรบ้าง?

ดี

in item1 TTT = 1 and somedata = 200
in item2 TTT = 1 and somedata = 99

กล่าวอีกนัยหนึ่งTTTคือข้อมูลที่ใช้ร่วมกันโดยอินสแตนซ์ทั้งหมดของประเภท ดังนั้นจึงไม่สมเหตุสมผลที่จะพูด

class Test {
         string somedata = "99";
         string getText() { return somedata; } 
  static string TTT = getText(); // error there is is no somedata at this point 
}

คำถามคือทำไมTTT ถึงคงที่หรือทำไม getText () ถึงไม่คงที่?

ลบstaticและควรผ่านข้อผิดพลาดนี้ - แต่หากไม่เข้าใจว่าประเภทของคุณทำอะไรมันเป็นเพียงพลาสเตอร์ติดจนกว่าจะเกิดข้อผิดพลาดถัดไป ข้อกำหนดgetText()ที่กำหนดให้เป็นแบบไม่คงที่คืออะไร?


มันคงที่เพราะฉันเรียกมันจากหลายไฟล์ในโครงการของฉัน เมื่อฉันลบ "คงที่" รหัสข้อผิดพลาดจะหายไป แต่ตอนนี้ฉันมีข้อผิดพลาดมากมายในไฟล์อื่น ๆ ที่ใช้ตัวแปรนี้
Chen M

แต่นั่นคือประเด็นของฉัน คุณต้องเข้าใจเมื่อทั้งสองสามารถใช้งานได้
เปรียญ

เมื่อฉันเพิ่มบรรทัด "ค่าคงที่การแจ้งเตือน = ค่าคงที่ใหม่ (); ในคลาสกิจกรรมหลักของฉันคอมไพล์ตกลง แต่ในโปรแกรมจำลองจะขัดข้องเมื่อกิจกรรมนี้ทำงาน
Chen M

12

มีคำตอบที่ดีพร้อมคำอธิบายว่าเหตุใดจึงไม่สามารถใช้ส่วนผสมของContextวิธีการgetText()ไม่คงที่กับstatic final Stringไฟล์.

คำถามที่ดีที่ควรถามคือทำไมคุณถึงต้องการทำสิ่งนี้? คุณกำลังพยายามโหลด a Stringจากstringsทรัพยากรของคุณและเติมค่าลงในpublic staticฟิลด์ ฉันคิดว่านี่เป็นเพื่อให้ชั้นเรียนอื่น ๆ ของคุณสามารถเข้าถึงได้? ถ้าเป็นเช่นนั้นไม่จำเป็นต้องทำเช่นนี้ ส่งผ่านContextไปยังชั้นเรียนอื่น ๆ ของคุณและโทรcontext.getText(R.string.TTT)จากภายใน

public class NonActivity {

    public static void doStuff(Context context) {
        String TTT = context.getText(R.string.TTT);
        ...
    }
}

และเพื่อเรียกสิ่งนี้จากคุณActivity:

NonActivity.doStuff(this);

วิธีนี้จะช่วยให้คุณสามารถเข้าถึงStringทรัพยากรของคุณได้โดยไม่จำเป็นต้องใช้public staticฟิลด์


1
ขอบคุณมากฉันเปลี่ยนไฟล์ทั้งหมดตามคำแนะนำของคุณ
Chen M

ฉันพยายามทำสิ่งนี้ แต่สำหรับสตริงอาร์เรย์และด้วยString a[] = context.getTextArray(R.array.myStringArray); ; อย่างไรก็ตามมันทำให้ฉันมีข้อผิดพลาดThe method getTextArray(int) is undefined for the type Context- ทำไมมันถึงไม่ได้กำหนดในขณะที่มันใช้งานได้กับ getText
ฤกษ์ดี 99

1
@ มงคล 99 เพียงเพราะ a Contextไม่มีวิธีการที่เรียกว่าgetTextArrayแต่มีgetText. บางทีคุณอาจกำลังคิดว่าResourcesมีอะไรบ้างgetTextArray
dave.c

ขอบคุณมาก! ส่งผ่านในทรัพยากรแทนที่จะเป็นบริบท (จากกิจกรรมไปสู่การไม่ใช้งาน) และ getStringArray ของฉันก็ใช้งานได้
ฤกษ์ดี

9

สำหรับคนอื่น ๆ ที่พบสิ่งนี้ในการค้นหา:

ฉันมักจะได้รับสิ่งนี้เมื่อฉันเรียกใช้ฟังก์ชันโดยไม่ได้ตั้งใจโดยใช้ชื่อคลาสแทนที่จะเป็นชื่อวัตถุ มักเกิดขึ้นเพราะฉันตั้งชื่อคล้ายกันเกินไป: P

กล่าวคือ:

MyClass myclass = new MyClass();

// then later

MyClass.someFunction();

เห็นได้ชัดว่านี่เป็นวิธีการคงที่ (ดีสำหรับบางครั้ง) แต่สิ่งที่ฉันอยากทำจริงๆ (ในกรณีส่วนใหญ่คือ)

myclass.someFunction();

มันเป็นความผิดพลาดที่โง่มาก แต่ทุกๆสองเดือนฉันเสียเวลาประมาณ 30 นาทีในการไปยุ่งกับ vars ในคำจำกัดความ "MyClass" เพื่อหาว่าฉันทำอะไรผิดเมื่อจริงๆมันเป็นแค่การพิมพ์ผิด

หมายเหตุตลก: stack overflow เน้นไวยากรณ์เพื่อให้ข้อผิดพลาดชัดเจนที่นี่


IDE ของคุณไม่เน้นเรื่องนี้ด้วยหรือ? ฉันเดาว่าคุณสามารถกำหนดค่าให้ทำได้ :)
Matthias Meid

2

คุณสามารถทำให้ตัวแปรของคุณไม่คงที่

public final String TTT =  (String) getText(R.string.TTT);

หรือทำให้เมธอด "getText" คงที่ (ถ้าเป็นไปได้ทั้งหมด)


2

getText เป็นสมาชิกของกิจกรรมของคุณดังนั้นจึงต้องถูกเรียกเมื่อมี "สิ่งนี้" ตัวแปรคงที่ของคุณจะเริ่มต้นเมื่อชั้นเรียนของคุณโหลดก่อนที่จะสร้างกิจกรรมของคุณ

เนื่องจากคุณต้องการให้ตัวแปรเริ่มต้นจากสตริงทรัพยากรจึงไม่สามารถคงที่ได้ หากคุณต้องการให้เป็นแบบคงที่คุณสามารถเริ่มต้นด้วยค่า String


2

คุณไม่สามารถอ้างอิงถึงตัวแปรคงที่จากวิธีการที่ไม่คงที่ เพื่อให้เข้าใจสิ่งนี้คุณต้องเข้าใจความแตกต่างระหว่างคงที่และไม่คงที่

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

ตอนนี้มาถึงคำถามของคุณเมื่อคุณใช้ตัวดำเนินการใหม่ () เราจะสร้างสำเนาของทุกไฟล์ที่ไม่คงที่สำหรับทุกออบเจ็กต์ แต่ไม่ใช่กรณีสำหรับฟิลด์คงที่ นั่นเป็นเหตุผลที่ทำให้เกิดข้อผิดพลาดเวลาคอมไพล์หากคุณอ้างอิงตัวแปรคงที่จากวิธีการไม่คงที่


0

คำถามนี้ไม่ใช่คำตอบใหม่และคำตอบที่มีอยู่ให้พื้นฐานทางทฤษฎีที่ดี ฉันแค่ต้องการเพิ่มคำตอบที่เป็นประโยชน์มากขึ้น

getText เป็นวิธีการของคลาสนามธรรมบริบทและเพื่อที่จะเรียกมันว่าเราต้องการอินสแตนซ์ของคลาสย่อย (กิจกรรมบริการแอปพลิเคชันหรืออื่น ๆ ) ปัญหาคือตัวแปรสุดท้ายแบบคงที่สาธารณะถูกเตรียมใช้งานก่อนที่จะสร้างอินสแตนซ์ของบริบทใด ๆ

มีหลายวิธีในการแก้ปัญหานี้:

  1. ทำให้ตัวแปรเป็นตัวแปรสมาชิก (ฟิลด์) ของกิจกรรมหรือคลาสย่อยอื่น ๆ ของบริบทโดยการลบตัวปรับแต่งแบบคงที่และวางไว้ในเนื้อหาคลาส
  2. ทำให้มันคงที่และชะลอการเริ่มต้นไปยังจุดต่อมา (เช่นในวิธี onCreate);
  3. กำหนดให้เป็นตัวแปรท้องถิ่นแทนการใช้งานจริง
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.