วิธีการสร้างอินสแตนซ์คลาสภายในที่ไม่คงที่ภายในวิธีการคงที่?


122

ฉันมีรหัสต่อไปนี้:

public class MyClass {

   class Inner {
     int s, e, p;
   }

   public static void main(String args[]) {
     Inner in;
   }
}

ถึงส่วนนี้รหัสก็ใช้ได้ แต่ฉันไม่สามารถสร้างอินสแตนซ์ 'in' ภายในวิธีการหลักเหมือนin = new Inner()ที่แสดงnon static field cannot be referenced in static contextได้

ฉันจะทำอย่างไร? ฉันไม่ต้องการที่จะทำให้ฉันInnerระดับคงที่


คำตอบ:


201

คุณต้องมีการอ้างอิงถึงคลาสชั้นนอกอื่น ๆ ด้วย

Inner inner = new MyClass().new Inner();

ถ้าอินเนอร์นิ่งก็จะเป็น

Inner inner = new MyClass.Inner();

53
คำตอบนี้ทำให้มุมมองชีวิตของฉันเปลี่ยนไป ด้านนอกใหม่ด้านใน ()? ไม่เคยคิดว่ามันเป็นไปได้ O_O
AlbeyAmakiir

1
สำหรับ static inner คุณแค่ทำ Inner inner = new Inner () ไม่ได้หรือ?
Can Lu

1
@CanLu เพื่อสร้างวัตถุสำหรับคลาสที่ซ้อนกันแบบคงที่ให้ใช้OuterClass.StaticNestedClass nestedObj = new OuterClass.StaticNestedClass(). Nested Classes
LittleLittleQ

37

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

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

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

นี่คือตัวอย่างโค้ดที่สาธิตไวยากรณ์สำหรับการสร้างคลาสภายในแบบคงที่และไม่คงที่:

public class MyClass {

    int a,b,c; // Some members for MyClass

    static class InnerOne {
        int s,e,p;
        void clearA() {
            //a = 0;  Can't do this ... no outer pointer
        }
    }

    class InnerTwo {
        //MyClass parentPointer;      Hidden pointer to outer instance
        void clearA() {         
            a = 0;
            //outerPointer.a = 0      The compiler generates this code
        }       
    }

    void myClassMember() {
        // The compiler knows that "this" is the outer reference to give
        // to the new "two" instance.
        InnerTwo two = new InnerTwo(); //same as this.new InnerTwo()
    }

    public static void main(String args[]) {

        MyClass outer = new MyClass();

        InnerTwo x = outer.new InnerTwo(); // Have to set the hidden pointer
        InnerOne y = new InnerOne(); // a "static" inner has no hidden pointer
        InnerOne z = new MyClass.InnerOne(); // In other classes you have to spell out the scope

    }

}

4

หากคุณต้องการสร้างnew Inner()จากภายในเมธอดให้ทำจากวิธีอินสแตนซ์ของคลาสMyClass:

public void main(){
  Inner inner = new Inner();
}

public static void main(String args[]){
  new MyClass().main();
}

0

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

import java.awt.Graphics;
import java.awt.Color;
import javax.swing.JPanel;
import javax.swing.JFrame;

public class Example {
    public class InnerClass extends JPanel {
        public void paint(Graphics g) {
            g.setColor(Color.BLACK);
            g.fillRect(getX(),getY(),getWidth(),getHeight());
            g.setColor(Color.RED);
            g.fillRect(5, 20, 195, 20);
            g.setColor(Color.BLACK);
            g.drawString("This was written by an inner class.", 10, 35);
        }
    }

    public void demonstrate() {
        InnerClass sc = new InnerClass();//<---this is key
        JFrame jf = new JFrame();
        jf.add(sc);
        jf.setSize(220, 130);
        jf.setLocation(450, 450);
        jf.show();
    }

    public static void main(String[] params) {
        Example e = new Example();//<---so is this
        e.demonstrate();//<---and this is also key
    }
}

ภาคผนวก: คุณ - สามารถสร้างอินสแตนซ์คลาสภายในแบบคงที่จากวิธีการแบบคงที่ รหัสประเภทนี้จำเป็นเพื่อสร้างอินสแตนซ์คลาสภายในที่ไม่คงที่จากภายในวิธีการแบบคงที่เท่านั้น
Herbert Samuel Jennings III
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.