ทำไมเราไม่สามารถมีวิธีการคงที่ในชั้นใน (ไม่คงที่)?


142

ทำไมเราไม่สามารถมีวิธีสแตติกในคลาสภายในที่ไม่คงที่ได้?

ถ้าฉันทำให้ชั้นในคงที่มันใช้งานได้ ทำไม?


4
เพราะตอนนี้ Java เป็นที่ COBOL เก่า :)
SES

บรรทัดล่างคือ: เพราะพวกเขายังไม่ได้ใช้งาน
intrepidis

1
'Non-static Inner' เป็นคำซ้ำซาก
มาร์ควิสแห่ง Lorne

หากคุณไม่ต้องการเปิดเผยชั้นในของคุณให้ผู้อื่นและหวังว่าจะมีวิธีการคงที่คุณสามารถใส่ตัวดัดแปลงทั้ง "ส่วนตัว" และ "คงที่" ในชั้นเรียนภายใน
Willie Z

คลาสภายในคือโดยนิยามไม่คงที่ คุณสามารถมีคลาสแบบซ้อน / สมาชิกแบบคงที่และคลาสแบบซ้อน / สมาชิกแบบไม่คงที่ หลังเป็นที่รู้จักกันว่าเป็นชั้นใน (การอ้างอิง: ส่วน 8.1.3 ของ JLS ระบุว่า " คลาสภายในเป็นคลาสที่ซ้อนกันซึ่งไม่ได้ประกาศชัดเจนหรือโดยปริยายstatic")
Erwin Bolwidt

คำตอบ:


111

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


7
ฉันรู้ว่าชั้นในมีความเกี่ยวข้องกับตัวอย่างของชั้นนอกและฉันรู้ว่ามันไม่มีประโยชน์อะไรที่เราสามารถประกาศสมาชิกคงที่ภายในชั้นใน แต่ฉันยังคงถามว่าทำไมชั้นในไม่สามารถประกาศสมาชิกคงที่ได้หรือไม่
Kareem

15
ใน C ++ คุณสามารถมีได้ดังนั้นนี่เป็นข้อบกพร่องในภาษา Java
อุตสาหกรรมยากล่อมประสาท

39
คำว่าบั๊ก ... ฉันไม่คิดว่าคำนั้นหมายถึงสิ่งที่คุณคิดว่ามันหมายถึง
เซทเนลสัน

24
วลีที่เหมาะสมกว่านี้น่าจะเป็น ไม่เข้าใจว่าทำไม Java ไม่อนุญาตให้ทำเช่นนี้ บางครั้งฉันต้องการให้คลาสภายในใช้คุณสมบัติของคลาสพาเรนต์ แต่เก็บเมธอดแบบสแตติกเพื่อการกำหนดเนมสเปซที่ดีขึ้น มีบางอย่างผิดปกติกับสิ่งนี้หรือไม่? :(
Angad

6
เผง ฉันต้องการที่จะเขียนชั้นในยูทิลิตี้ วิธีการบางอย่างจะได้ประโยชน์จากการเข้าถึงคลาสภายนอกดังนั้นฉันไม่สามารถทำให้เป็นแบบสแตติกได้ แต่วิธีการบางอย่างเป็นเพียงฟังก์ชันยูทิลิตี้ ทำไมฉันไม่สามารถโทรA.B.sync(X)หรือแม้กระทั่ง (จากภายใน A) B.sync(x)?
Edward Falk

44

มีจุดไม่มากที่จะอนุญาตให้ใช้วิธีการคงที่ในชั้นในแบบคงที่; คุณจะเข้าถึงมันอย่างไร คุณไม่สามารถเข้าถึง (อย่างน้อยเริ่มต้น) อินสแตนซ์ของคลาสภายในที่ไม่คงที่โดยไม่ต้องผ่านอินสแตนซ์ของคลาสภายนอก ไม่มีวิธีคงที่อย่างหมดจดในการสร้างชั้นในแบบไม่คงที่

สำหรับคลาสภายนอกOuterคุณสามารถเข้าถึงวิธีแบบคงที่test()เช่นนี้:

Outer.test();

สำหรับคลาสภายในแบบสแตติกInnerคุณสามารถเข้าถึงวิธีสแตติกได้innerTest()ดังนี้:

Outer.Inner.innerTest();

อย่างไรก็ตามหากInnerไม่ใช่แบบคงที่ไม่มีวิธีแบบคงที่ในการอ้างอิงวิธีinnertestนี้ คลาสภายในที่ไม่คงที่นั้นเชื่อมโยงกับอินสแตนซ์เฉพาะของคลาสภายนอก ฟังก์ชั่นจะแตกต่างจากค่าคงที่ซึ่งการอ้างอิงถึงOuter.Inner.CONSTANTถูกรับประกันว่าจะไม่คลุมเครือในลักษณะที่การเรียกใช้ฟังก์ชันOuter.Inner.staticFunction();ไม่ได้ สมมติว่าคุณมีInner.staticFunction()สายgetState()ที่กำหนดไว้Outerซึ่งถูกกำหนดไว้ในหากคุณพยายามที่จะเรียกใช้ฟังก์ชั่นแบบคงที่ตอนนี้คุณมีการอ้างอิงที่ไม่ชัดเจนกับชั้นใน นั่นคือในกรณีของคลาสภายในที่คุณเรียกใช้ฟังก์ชันสแตติก มันเป็นเรื่องสำคัญ ดูว่าไม่มีวิธีที่คงที่อย่างแท้จริงในการอ้างอิงวิธีการคงที่เนื่องจากการอ้างอิงโดยนัยไปยังวัตถุด้านนอก

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

หากคุณต้องการวิธีการคงที่ในชั้นเรียนแบบไม่คงที่จริงๆแล้วคุณอาจต้องพิจารณาการออกแบบของคุณใหม่


6
-1 ฉันไม่เห็นด้วยกับมุมที่คุณถ่ายที่นี่ แน่นอนว่าเราสามารถอ้างอิงประเภทชั้นในได้ตัวอย่างเช่นOuter.Inner i = new Outer().new Inner();นอกจากนี้คลาสภายในยังได้รับอนุญาตให้ประกาศค่าคงที่แบบคงที่ตาม JLS §15.28
พอล Bellora

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

25
"มีจุดไม่มากที่จะอนุญาตให้ใช้วิธีการคงที่ในชั้นในแบบไม่คงที่คุณจะเข้าถึงได้อย่างไร?" คุณจะเรียกเช่นเดียวกับคุณสามารถเข้าถึงOuter.Inner.staticMethod() Outer.Inner.CONSTANT"คุณไม่สามารถเข้าถึง ... อินสแตนซ์ของคลาสภายในที่ไม่คงที่โดยไม่ต้องผ่านอินสแตนซ์ของคลาสภายนอก" ทำไมคุณต้องการอินสแตนซ์? คุณไม่จำเป็นต้องตัวอย่างของการเรียกร้องOuter Outer.staticMethod()ฉันรู้ว่านี่เป็น nitpicky แต่ประเด็นของฉันคือมันไม่เหมาะสมที่จะวางกรอบคำตอบของคุณด้วยวิธีนี้ IMHO นักออกแบบภาษาสามารถอนุญาตได้หากพวกเขาต้องการ
Paul Bellora

1
ความแตกต่างระหว่างOuter.Inner.CONSTANTและOuter.Inner.staticMethod()คือการอ้างอิงถึงค่าคงที่ไม่มีโอกาสที่จะอ้างอิงถึงอินสแตนซ์Outerที่Innerมีอินสแตนซ์ การอ้างอิงทั้งหมดเพื่อOuter.staticMethod()แบ่งปันสถานะที่แน่นอนเดียวกัน การอ้างอิงทั้งหมดเพื่อOuter.Inner.CONSTANTแบ่งปันสถานะที่แน่นอนเดียวกัน อย่างไรก็ตามการอ้างอิงไปยังOuter.Inner.staticMethod()มีความคลุมเครือที่: "คงที่" Innerรัฐไม่คงที่อย่างแท้จริงเนื่องจากการอ้างอิงโดยปริยายชั้นนอกในกรณีของแต่ละ ไม่มีวิธีที่ชัดเจนในการเข้าถึง
Eddie

3
@Eddie คุณไม่สามารถดูได้ที่สาขาเช่นในวิธีการแบบคงที่จึงมีความขัดแย้งใด ๆ Outer.thisที่เกี่ยวข้องกับการไม่สามารถที่จะดูที่สนามอินสแตนซ์โดยปริยาย ฉันเห็นด้วยกับนักออกแบบภาษาจาวาว่าไม่มีเหตุผลที่จะอนุญาตให้ใช้วิธีการคงที่หรือไม่คงที่เขตข้อมูลสุดท้ายในชั้นเรียนชั้นในเพราะทุกอย่างในชั้นภายในควรอยู่ในบริบทของชั้นล้อมรอบ
Theodore Murdock

20

ฉันมีทฤษฎีซึ่งอาจหรืออาจไม่ถูกต้อง

ก่อนอื่นคุณควรรู้บางสิ่งเกี่ยวกับวิธีใช้คลาสภายในใน Java สมมติว่าคุณมีคลาสนี้:

class Outer {
    private int foo = 0;
    class Inner implements Runnable {
        public void run(){ foo++; }
    }
    public Runnable newFooIncrementer(){ return new Inner(); }
}

เมื่อคุณคอมไพล์มันโค้ดที่สร้างขึ้นจะมีลักษณะเหมือนกับว่าคุณเขียนอะไรแบบนี้:

class Outer {
    private int foo = 0;
    static class Inner implements Runnable {
        private final Outer this$0;
        public Inner(Outer outer){
            this$0 = outer;
        }
        public void run(){ this$0.foo++; }
    }
    public Runnable newFooIncrementer(){ return new Inner(this); }
}

ทีนี้ถ้าเราอนุญาตวิธีการแบบสแตติกในคลาสภายในแบบไม่คงที่คุณอาจต้องการทำสิ่งนี้

class Outer {
    private int foo = 0;
    class Inner {
        public static void incrFoo(){ foo++; }
    }
}

... ซึ่งดูสมเหตุสมผลพอสมควรเนื่องจากInnerคลาสดูเหมือนจะมีหนึ่งชาติต่อหนึ่งOuterอินสแตนซ์ แต่อย่างที่เราเห็นข้างต้นคลาสภายในที่ไม่คงที่นั้นเป็นเพียงน้ำตาลซินแทคติคสำหรับคลาส "ภายใน" แบบคงที่ดังนั้นตัวอย่างสุดท้ายจะเทียบเท่ากับ:

class Outer {
    private int foo = 0;
    static class Inner {
        private final Outer this$0;
        public Inner(Outer outer){
            this$0 = outer;
        }
        public static void incrFoo(){ this$0.foo++; }
    }
}

... ซึ่งไม่สามารถใช้งานได้อย่างชัดเจนเนื่องจากthis$0ไม่คงที่ การเรียงลำดับนี้อธิบายว่าทำไมไม่อนุญาตให้ใช้วิธีการคงที่ (แม้ว่าคุณสามารถสร้างอาร์กิวเมนต์ที่คุณสามารถอนุญาตให้ใช้วิธีการแบบคงที่ตราบใดที่พวกเขาไม่ได้อ้างอิงวัตถุที่ปิดล้อม) และทำไมคุณไม่สามารถมีเขตข้อมูลคงที่ไม่ใช่ครั้งสุดท้าย มันจะตอบโต้ได้ง่ายหากอินสแตนซ์ของคลาสภายในที่ไม่คงที่จากวัตถุต่าง ๆ ที่ใช้ร่วมกัน "สถานะคงที่") นอกจากนี้ยังอธิบายว่าทำไมเขตสุดท้ายจะได้รับอนุญาต (ตราบเท่าที่พวกเขาไม่ได้อ้างอิงวัตถุล้อมรอบ)


7
แต่นั่นเป็นเพียงข้อผิดพลาดในการพิมพ์ "พยายามเข้าถึงตัวแปรที่ไม่คงที่จากบริบทแบบสแตติก" ไม่แตกต่างจากถ้าวิธีการระดับคงที่ระดับสูงสุดพยายามเข้าถึงตัวแปรอินสแตนซ์ของคลาสของตัวเอง
Lawrence Dol

2
ฉันชอบแอนเซอร์นี้เพราะมันอธิบายได้ว่าทำไมมันถึงเป็นไปไม่ได้ทางเทคนิคถึงแม้ว่ามันจะดูเป็นไปได้
LoPoBo

@ustafc ฉันคิดว่านั่นเป็นคำอธิบายที่ยอดเยี่ยม แต่ดังที่ลอว์เรนซ์ชี้ให้เห็นมันเป็นเพียงความล้มเหลวเนื่องจากการอ้างอิงถึงฟู แต่ถ้าฉันต้องการเขียนpublic static double sinDeg(double theta) { ... }คลาสคณิตศาสตร์อรรถประโยชน์ชั้นใน?
Edward Falk

6

เหตุผลเดียวคือ "ไม่ต้อง" ดังนั้นทำไมต้องสนใจที่จะสนับสนุน?

วากยสัมพันธ์ไม่มีเหตุผลที่จะห้ามไม่ให้ชั้นในจากการมีสมาชิกแบบคงที่ แม้ว่าอินสแตนซ์ของInnerจะเชื่อมโยงกับอินสแตนซ์ของOuterก็ยังคงเป็นไปได้ที่จะใช้Outer.Inner.myStaticเพื่ออ้างอิงสมาชิกคงที่ของInnerถ้าจาวาตัดสินใจที่จะทำเช่นนั้น

หากคุณต้องการแบ่งปันบางสิ่งในทุกกรณีของInnerคุณก็สามารถทำให้พวกเขาOuterเป็นสมาชิกแบบคงที่ สิ่งนี้ไม่ได้เลวร้ายยิ่งไปกว่าการที่คุณใช้สมาชิกแบบสแตติกInnerซึ่งOuterยังคงสามารถเข้าถึงสมาชิกส่วนตัวใด ๆ ได้Inner(ไม่ปรับปรุง encapsulation)

หากคุณต้องการแบ่งปันบางสิ่งในทุก ๆ อินสแตนซ์ที่Innerสร้างโดยouterวัตถุหนึ่งชิ้นมันเหมาะสมกว่าที่จะทำให้พวกเขาอยู่ในOuterชั้นเรียนในฐานะสมาชิกสามัญ

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


คลาสภายในไม่ใช่ "ต้อง" อย่างใดอย่างหนึ่ง แต่เป็นภาษาที่ไม่ให้เรียนภายในก็ควรให้การใช้งานที่สมบูรณ์และมีความหมายของพวกเขา
intrepidis

4

จาก: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

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

คำอธิบายของ Oracle นั้นผิวเผินและเป็นคลื่น เนื่องจากไม่มีเหตุผลทางเทคนิคหรือวากยสัมพันธ์ในการจองสมาชิกแบบคงที่ภายในคลาสภายใน (อนุญาตในภาษาอื่นเช่น C #) แรงจูงใจของนักออกแบบ Java จึงน่าจะเป็นเรื่องของแนวคิดและ / หรือเรื่องความสะดวกสบายทางเทคนิค

นี่คือการเก็งกำไรของฉัน:

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

ธรรมชาติของสมาชิกแบบสแตติก (ซึ่งไม่ใช่แบบเชิงวัตถุ) ขัดแย้งกับอินสแตนซ์ที่ขึ้นอยู่กับวิญญาณของคลาสภายใน (ซึ่งเป็นแบบวัตถุ) เนื่องจากคุณสามารถอ้างอิง / เรียกสมาชิกแบบสแตติกของคลาสภายในโดยไม่มีอินสแตนซ์คลาสภายนอกโดย ใช้ชื่อคลาสภายในที่ผ่านการรับรอง

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

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

อาจไม่ใช่เหตุผลที่มั่นคง แต่ IMO ทำให้เข้าใจถึงคำพูดคร่าวๆของออราเคิลในเรื่องนี้ได้มากที่สุด


3

คำตอบสั้น ๆ : โมเดลจิตโปรแกรมเมอร์ส่วนใหญ่มีขอบเขตการทำงานอย่างไรไม่ใช่โมเดลที่ใช้โดย javac การจับคู่โมเดลที่ใช้งานง่ายยิ่งขึ้นนั้นจำเป็นต้องมีการเปลี่ยนแปลงครั้งใหญ่ในการทำงานของ javac

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

class Outer {
   int outID;

   class Inner {
      static int nextID;
      int id = nextID++;

      String getID() {
         return outID + ":" + id;
      }
   }
}

พิจารณาสิ่งที่เกิดขึ้นใน getID () เมื่อฉันใช้ตัวระบุที่ไม่มีเงื่อนไข "outID" ขอบเขตที่ตัวระบุนี้ปรากฏขึ้นมีลักษณะดังนี้:

Outer -> Inner -> getID()

ที่นี่อีกครั้งเพราะนี่เป็นเพียงวิธีการทำงานของ javac ระดับ "Outer" ของขอบเขตประกอบด้วยสมาชิกทั้งแบบสแตติกและอินสแตนซ์ของ Outer นี่คือความสับสนเพราะเรามักจะบอกให้คิดว่าส่วนคงที่ของชั้นเรียนเป็นระดับอื่นของขอบเขต:

Outer static -> Outer instance -> instanceMethod()
         \----> staticMethod()

ในวิธีการคิดเกี่ยวกับเรื่องนี้แน่นอน staticMethod () สามารถเห็นสมาชิกคงที่ของ Outer แต่ถ้านั่นเป็นวิธีการทำงานของ javac การอ้างอิงตัวแปรอินสแตนซ์ในวิธีการแบบคงที่จะส่งผลให้เกิดข้อผิดพลาด "ชื่อไม่สามารถแก้ไขได้" สิ่งที่เกิดขึ้นจริงคือชื่อพบในขอบเขต แต่จากนั้นระดับการตรวจสอบเพิ่มเติมจะเริ่มขึ้นและแสดงให้เห็นว่าชื่อถูกประกาศในบริบทอินสแตนซ์และถูกอ้างอิงจากบริบทแบบคงที่

ตกลงสิ่งนี้เกี่ยวข้องกับคลาสภายในอย่างไร อย่างไร้เดียงสาเราคิดว่าไม่มีเหตุผลในการเรียนภายในไม่สามารถมีขอบเขตคงที่เพราะเรากำลังภาพขอบเขตการทำงานเช่นนี้:

Outer static -> Outer instance -> Inner instance -> getID()
         \------ Inner static ------^

กล่าวอีกนัยหนึ่งการประกาศแบบสแตติกในคลาสภายในและการประกาศอินสแตนซ์ในคลาสภายนอกนั้นอยู่ในขอบเขตภายในบริบทอินสแตนซ์ของคลาสชั้นใน ทั้งสองซ้อนกันอยู่ในขอบเขตคงที่ของ Outer

นั่นไม่ใช่วิธีการทำงานของ javac - มีขอบเขตระดับเดียวสำหรับสมาชิกแบบสแตติกและอินสแตนซ์และขอบเขตจะทำรังอย่างเคร่งครัดเสมอ แม้แต่การสืบทอดจะถูกนำไปใช้โดยการคัดลอกการประกาศในคลาสย่อยแทนการแยกและค้นหาขอบเขตซูเปอร์คลาส

เพื่อสนับสนุนสมาชิกแบบคงที่ของคลาสภายใน javac จะต้องแยกขอบเขตแบบคงที่และอินสแตนซ์และสนับสนุนการแยกสาขาและเข้าร่วมลำดับชั้นของขอบเขตหรือจะต้องขยายแนวคิดแบบ "บริบทบริบท" แบบบูลแบบง่าย ๆ เพื่อเปลี่ยนชนิดของบริบทในทุกระดับ ของคลาสที่ซ้อนกันในขอบเขตปัจจุบัน


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

3

ทำไมเราไม่สามารถมีวิธีสแตติกในคลาสภายในที่ไม่คงที่ได้?

หมายเหตุ:คลาสที่ซ้อนกันแบบไม่คงที่เรียกว่าคลาสภายในดังนั้นคุณจึงไม่มีnon-static inner classเช่นนั้น

อินสแตนซ์ของคลาสภายในไม่มีอยู่โดยไม่มีอินสแตนซ์ที่สอดคล้องกันของคลาสภายนอก คลาสภายในไม่สามารถประกาศสมาชิกแบบคงที่นอกเหนือจากค่าคงที่เวลาคอมไพล์ staticถ้ามันไม่ได้รับอนุญาตจากนั้นก็จะได้รับความคลุมเครือเกี่ยวกับความหมายของ ในกรณีนั้นจะมีความสับสน:

  1. มันหมายความว่ามีเพียงหนึ่งอินสแตนซ์ใน VM?
  2. หรือเพียงหนึ่งครั้งต่อวัตถุภายนอก?

นั่นคือเหตุผลที่นักออกแบบอาจตัดสินใจไม่จัดการกับปัญหานี้เลย

ถ้าฉันทำให้ชั้นในคงที่มันใช้งานได้ ทำไม

คุณไม่สามารถสร้างคลาสภายในให้คงที่ได้ แต่คุณสามารถประกาศคลาสคงที่ว่าซ้อนกัน ในกรณีนี้คลาสที่ซ้อนกันนี้เป็นส่วนหนึ่งของคลาสภายนอกและสามารถมีสมาชิกแบบสแตติกโดยไม่มีปัญหาใด ๆ


3

หัวข้อนี้ได้รับความสนใจจากหลาย ๆ คน แต่ฉันจะพยายามอธิบายด้วยคำศัพท์ที่ง่ายที่สุด

ประการแรกด้วยการอ้างอิงถึงhttp://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1คลาสหรืออินเทอร์เฟซจะเริ่มต้นได้ทันทีก่อนที่จะเกิดขึ้น / เรียกใช้ครั้งแรก ของสมาชิกใด ๆ ซึ่งนำหน้าด้วยคำหลักแบบคงที่

  1. ดังนั้นถ้าเราใส่สมาชิกแบบคงที่ภายในคลาสภายในมันจะนำไปสู่การเริ่มต้นของคลาสภายในไม่จำเป็นต้องเป็นคลาสภายนอก / ปิดล้อม ดังนั้นเราจึงขัดขวางลำดับการเริ่มต้นของคลาส

  2. พิจารณาความจริงที่ว่าคลาสภายในที่ไม่คงที่นั้นเชื่อมโยงกับอินสแตนซ์ของคลาสที่ล้อมรอบ / ภายนอก ดังนั้นการเชื่อมโยงกับอินสแตนซ์จะหมายถึงว่าคลาสภายในจะอยู่ในอินสแตนซ์ของคลาสภายนอกและจะแตกต่างกันระหว่างอินสแตนซ์

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


2

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


เบ็นดิคต์คุณหมายความว่าอย่างไรเมื่อคุณพูดว่า "คลาสซ้อนแบบคงที่เป็นเพียงวิธีการจัดกลุ่ม"
Ankur

0

สมมติว่ามีสองกรณีของคลาสนอกและพวกเขาทั้งสองมีอินสแตนซ์ชั้นภายในตอนนี้ถ้าชั้นในมีสมาชิกคงที่แล้วมันจะเก็บสำเนาของสมาชิกนั้นเพียงหนึ่งในพื้นที่กองในกรณีนี้วัตถุทั้งชั้นนอกจะอ้างถึงนี้ สำเนาเดียว & พวกเขาสามารถแก้ไขได้ด้วยกันซึ่งอาจทำให้สถานการณ์ "สกปรกอ่าน" ดังนั้นเพื่อป้องกัน Java นี้ได้ใช้ข้อ จำกัด นี้จุดแข็งอีกประการหนึ่งเพื่อสนับสนุนอาร์กิวเมนต์นี้คือ Java อนุญาตให้สมาชิกแบบคงที่สุดท้ายที่นี่ เปลี่ยนจากวัตถุชั้นนอกอย่างใดอย่างหนึ่ง โปรดให้ฉันถ้าฉันผิด


0

ก่อนอื่นทำไมใครบางคนต้องการกำหนดสมาชิกแบบคงที่ในชั้นในแบบไม่คงที่? คำตอบคือเพื่อให้สมาชิกชั้นนอกสามารถใช้สมาชิกคงที่ที่มีชื่อชั้นในเท่านั้นใช่มั้ย

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

ชอบรหัสด้านล่าง

public class Outer {

  class Inner {

    public static void method() {

    }

  }

}

สามารถเขียนได้เช่นนี้

public class Outer {

  void method() {

   }

   class Inner {


  }

}

ดังนั้นในความคิดของฉันที่จะไม่ซับซ้อนนักออกแบบโค้ดจาวาไม่อนุญาตให้ใช้งานฟังก์ชันนี้หรือเราอาจเห็นฟังก์ชั่นนี้ในรุ่นต่อไปที่มีคุณสมบัติเพิ่มเติม


0

พยายามที่จะรักษาระดับเป็นสนามปกติแล้วคุณจะเข้าใจ

//something must be static. Suppose something is an inner class, then it has static keyword which means it's a static class
Outer.something 

-1

มันไม่มีประโยชน์ที่จะให้สมาชิกชั้นในคงที่เพราะคุณจะไม่สามารถเข้าถึงพวกเขาได้ตั้งแต่แรก

คิดเกี่ยวกับสิ่งนี้เพื่อเข้าถึงสมาชิกแบบคงที่คุณใช้ className.memberName ,, ในกรณีของเรามันควรเป็นสิ่งที่ต้องการ


-2

คุณได้รับอนุญาตวิธีการคงที่ในชั้นเรียนที่ซ้อนกันคงที่ ตัวอย่างเช่น

public class Outer {

  public static class Inner {

    public static void method() {

    }
  }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.