Java - ไม่สามารถเข้าถึงอินสแตนซ์ของประเภท Foo ได้


314

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

class Hello {
    class Thing {
        public int size;

        Thing() {
            size = 0;
        }
    }

    public static void main(String[] args) {
        Thing thing1 = new Thing();
        System.out.println("Hello, World!");
    }
}

ฉันรู้ว่าThingไม่ทำอะไรเลย แต่ Hello, World ของฉันโปรแกรมรวบรวมได้โดยไม่ต้อง เป็นคลาสที่ฉันกำหนดไว้เท่านั้นที่ทำให้ฉันล้มเหลว

และมันก็ปฏิเสธที่จะรวบรวม ฉันไปNo enclosing instance of type Hello is accessible."ที่บรรทัดที่สร้างสิ่งใหม่ ฉันเดาทั้ง:

  1. ฉันมีปัญหาระดับระบบ (ทั้งใน DrJava หรือติดตั้ง Java ของฉัน) หรือ
  2. ฉันมีความเข้าใจผิดขั้นพื้นฐานเกี่ยวกับวิธีการสร้างโปรแกรมการทำงานใน java

ความคิดใด ๆ


คำตอบ:


483

static class Thing จะทำให้โปรแกรมของคุณทำงาน

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

หากคุณประกาศว่าเป็นคลาสแบบสแตติกแทนนั่นคือคลาส "ซ้อน" ซึ่งไม่ต้องการสิ่งใดเป็นพิเศษ Helloอินสแตนซ์


นี่ก็หมายความว่าถ้าฉันยกตัวอย่างสิ่งouter classนั้นnon-static inner classจะถูกสร้างขึ้นเช่นกันแม้ว่าฉันจะไม่ใช้มันที่ไหน
mr5

ไม่ทุกชิ้นส่วนของชั้นในจะต้องมีผู้ปกครอง แต่ผู้ปกครองสามารถมีลูกจำนวนเท่าใดก็ได้รวมทั้ง 0
jacobm

92

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

ในรหัสของคุณคุณกำลังพยายามสร้างตัวอย่างของ Thingจากบริบทแบบคงที่ นั่นคือสิ่งที่คอมไพเลอร์บ่น

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

  • ย้ายThingออกจากHelloชั้นเรียน

  • เปลี่ยนThingเป็นstaticคลาสซ้อน

    static class Thing
  • สร้างอินสแตนซ์ของก่อนที่จะสร้างตัวอย่างของHelloThing

    public static void main(String[] args)
    {
        Hello h = new Hello();
        Thing thing1 = h.new Thing(); // hope this syntax is right, typing on the fly :P
    }

ทางออกสุดท้าย ( คลาสที่ไม่คงที่แบบคงที่ ) จะมีผลบังคับใช้หากอินสแตนซ์ใด ๆ ของการThingขึ้นอยู่กับอินสแตนซ์Helloที่จะมีความหมาย ตัวอย่างเช่นถ้าเรามี:

public class Hello {
    public int enormous;

    public Hello(int n) {
        enormous = n;
    }

    public class Thing {
        public int size;

        public Thing(int m) {
            if (m > enormous)
                size = enormous;
            else
                size = m;
        }
    }
    ...
}

ความพยายามแบบดิบ ๆ ในการสร้างออบเจ็กต์ของคลาสThingเช่นใน:

Thing t = new Thing(31);

จะเป็นปัญหาเนื่องจากจะไม่มีenormousค่าที่ชัดเจนในการทดสอบ 31 กับมัน อินสแตนซ์hของHelloคลาสภายนอกมีความจำเป็นเพื่อให้h.enormousค่านี้:

...
Hello h = new Hello(30);
...
Thing t = h.new Thing(31);
...

เพราะมันไม่ได้หมายความว่าถ้ามันไม่ได้ThingHello

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับคลาสที่ซ้อนกัน / ภายใน: คลาสที่ ซ้อนกัน (แบบฝึกหัด Java)


คำตอบของคุณมีทั้งแบบครอบคลุมและแบบสังเคราะห์ แม้ว่าฉันจะรู้สึกแปลก (สำหรับฉันอย่างน้อย) ไวยากรณ์ก็ถูกต้อง
boumbh

หากใครยังคงได้รับข้อผิดพลาดไวยากรณ์Thing thing1 <<HelloInstantiation>>.new Thing()เป็นกุญแจสำคัญ Thing thing1 new <<HelloInstantiation>>.Thing()ผมใช้เวลาไม่กี่นาทีสับสนโดยใช้ไวยากรณ์ = P
skia.heliou

1
@ skia.heliou ขอบคุณ! ฉันกำลังสร้างคลาสตัวช่วยและตัวแปรแบบสแตติก (หรือแม้แต่คลาส) ไม่เพียง แต่กำจัดขอบเขต แต่พวกเขามักจะไม่มีประสิทธิภาพ จำเป็นต้องระบุอาร์กิวเมนต์ของรันไทม์ทำให้รำคาญที่จะใช้วิธีการหลัก นี่คือทั้งหมดที่ฉันต้องการและสิ่งที่ฉันกำลังมองหา
รถเข็นที่ถูกทอดทิ้ง

25

ดี ... คำตอบที่ดีมากมาย แต่ฉันต้องการเพิ่มมากขึ้น การดูข้อมูลสั้น ๆ เกี่ยวกับคลาสภายในใน Java- Java ช่วยให้เราสามารถกำหนดคลาสภายในคลาสอื่นได้

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

  2. มันสามารถทำให้โค้ดบำรุงรักษาได้มากขึ้นเนื่องจากคลาสถูกจัดกลุ่มแบบโลจิคัลร่วมกันรอบ ๆ ตำแหน่งที่ต้องการ

  3. คลาสภายในมีการเข้าถึงตัวแปรอินสแตนซ์และวิธีการของคลาสที่ประกอบด้วย

เรามีสามประเภทหลัก Inner Classes

  1. ภายในท้องถิ่น
  2. ชั้นในคงที่
  3. ชั้นในแบบไม่เปิดเผยตัว

ประเด็นสำคัญที่ควรจดจำ

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

ลองดูแนวคิดข้างต้นจริง ๆ แล้ว _

public class MyInnerClass {

public static void main(String args[]) throws InterruptedException {
    // direct access to inner class method
    new MyInnerClass.StaticInnerClass().staticInnerClassMethod();

    // static inner class reference object
    StaticInnerClass staticInnerclass = new StaticInnerClass();
    staticInnerclass.staticInnerClassMethod();

    // access local inner class
    LocalInnerClass localInnerClass = new MyInnerClass().new LocalInnerClass();
    localInnerClass.localInnerClassMethod();

    /*
     * Pay attention to the opening curly braces and the fact that there's a
     * semicolon at the very end, once the anonymous class is created:
     */
    /*
     AnonymousClass anonymousClass = new AnonymousClass() {
         // your code goes here...

     };*/
 }

// static inner class
static class StaticInnerClass {
    public void staticInnerClassMethod() {
        System.out.println("Hay... from Static Inner class!");
    }
}

// local inner class
class LocalInnerClass {
    public void localInnerClassMethod() {
        System.out.println("Hay... from local Inner class!");
    }
 }

}

ฉันหวังว่าสิ่งนี้จะช่วยทุกคน โปรด อ้างอิงเพิ่มเติม


การปรับปรุงที่แนะนำ: ตั้งชื่อ MyOuterClass ชั้นหนึ่งเอาความคิดเห็นออกจากรอบ AnonymousClass
Noumenon

9

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

static class Thing

9

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

 public class PQ {

    public static void main(String[] args) {

        // create dog object here
        Dog dog = new PQ().new Dog();
        //OR
        PQ pq = new PQ();
        Dog dog1 = pq.new Dog();
    }

    abstract class Animal {
        abstract void checkup();
    }

    class Dog extends Animal {
        @Override
        void checkup() {
            System.out.println("Dog checkup");

        }
    }

    class Cat extends Animal {
        @Override
        void checkup() {
            System.out.println("Cat Checkup");

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