ไม่ใช่คลาส Java ที่ล้อมรอบ


366

ฉันกำลังพยายามสร้างเกม Tetris และฉันได้รับข้อผิดพลาดของคอมไพเลอร์

Shape is not an enclosing class

เมื่อฉันพยายามสร้างวัตถุ

public class Test {
    public static void main(String[] args) {
        Shape s = new Shapes.ZShape();
    }
}

ฉันใช้คลาสภายในสำหรับแต่ละรูปร่าง นี่คือส่วนหนึ่งของรหัสของฉัน

public class Shapes {
    class AShape {
    }
    class ZShape {
    }
}

ผมทำอะไรผิดหรือเปล่า ?


160
new Shape().new ZShape();. คลาสZShapeต้องการอินสแตนซ์การปิดล้อมเพื่อให้อินสแตนซ์
Sotirios Delimanolis

4
ย้ายคลาสภายในเพื่อแยกไฟล์
Dimmduh

ความคิดเห็น @Dimmduh ควรเป็นคำตอบในกรณีนี้ ไม่ควรเป็นคลาสภายใน การย้ายพวกเขาจะระบุปัญหาอื่น ๆ ด้วยคลาส Shape ที่มีอยู่
ยิระมะยาห์อดัมส์มี. ค.

จะไม่ตอบคำถามที่นี่ แต่ฉันสามารถขอแนะนำให้ใช้มรดกที่นี่ที่AShapeและขยายชั้นฐานZShape Shapesชั้นเรียนการสร้างรังไม่ใช่การออกแบบที่ดีสำหรับปัญหานี้
Paramvir Singh Karwal

คำตอบ:


492

ZShape ไม่คงที่ดังนั้นจึงต้องการอินสแตนซ์ของคลาสภายนอก

ทางออกที่ง่ายที่สุดคือการสร้าง ZShape และคลาสที่ซ้อนกันstaticหากคุณทำได้

ฉันจะทำฟิลด์ใดก็ได้finalหรือstatic finalคุณสามารถทำได้เช่นกัน


13
ทำZShape staticทั้งหมดขัดแย้งกับวัตถุประสงค์ของสิ่งที่เขาพยายามที่จะทำซึ่งเป็น instantiate ZShapeสำเนาของ
Cardano

17
@Cardano staticทำให้มันง่ายขึ้นไม่ยาก
Peter Lawrey

12
อีกวิธีง่ายๆที่จะทำให้ชั้นล้อมรอบ instantiate ระดับชั้นคือได้รับ ZShape ZShape myShape = new Shape().instantiateZShape();วิธีนี้: มันบอกเป็นนัยว่า ZShape ที่คุณได้รับไม่มีอยู่จริงหากไม่มีรูปร่างซึ่งเป็นเจตนาที่นี่
วินซ์

@Peter Lawrey คุณทราบได้อย่างไรว่าอินสแตนซ์ Shape ทั้งหมดต้องใช้ ZShape เดียวกัน ฉันไม่ได้รับจากแหล่งที่มาของเขา
เหลือเชื่อ

2
มี 2 ​​กรณีถ้าเราต้องการสแตติกหรืออินสแตนซ์ การทำให้เป็นสถิตจะไม่ช่วยเสมอ
Yogesh Chuahan

177

สมมติว่า RetailerProfileModel เป็นคลาสหลักของคุณและ RetailerPaymentModel เป็นคลาสภายในที่อยู่ภายใน คุณสามารถสร้างวัตถุของชั้นภายในภายนอกชั้นเรียนดังต่อไปนี้:

RetailerProfileModel.RetailerPaymentModel paymentModel
        = new RetailerProfileModel().new RetailerPaymentModel();

34
คำตอบนี้มีประโยชน์จริง ๆ ฉันไม่เคยรู้ว่าคุณสามารถโทรหาใหม่สองครั้งติดต่อกัน (และฉันทำ java มา 8 ปีแล้ว!)
PaulBGD

1
คุณสามารถเรียกผู้ดำเนินการรายใหม่ ๆ ได้หลายครั้งจนกว่าคุณจะไม่ต้องการให้การอ้างอิงของวัตถุนั้น
Vishal Kumar

1
หากวัตถุของคลาสภายในสร้างด้วยวิธีนี้มันจะเข้าถึงสมาชิกของคลาสภายนอกได้อย่างไร
Xingang Huang

1
ภายในคลาสภายในนั้นคุณสามารถใช้ OuterClass.this ฉันไม่คิดว่าจะมีวิธีการรับอินสแตนซ์จากนอกรหัสของคลาสภายใน แน่นอนคุณสามารถแนะนำทรัพย์สินของคุณเอง: public OuterClass getOuter () {return OuterClass.this; }
Vishal Kumar

ใช้งานได้สำหรับการทดสอบ:underTest = Mockito.mock(Outer.class).new InnerNonStaticClass();
felvhage

48

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

ตัวอย่าง:

class Outer
{
    class Inner
    {
        //...
    }
}

ดังนั้นในกรณีเช่นนี้คุณสามารถทำสิ่งที่ชอบ:

Outer o = new Outer();
Outer.Inner obj = o.new Inner();

สิ่งที่เกี่ยวกับ Outer.Inner obj = (new outer). Inner ใหม่ ();
Hussain KMR Behestee

1
@HussainKMRBehestee ไม่ว่าจะไม่ทำงานอย่างแน่นอน อย่างไรก็ตามสิ่งนี้จะใช้ได้Outer.Inner obj = new Outer().new Inner();
Amit Upadhyay

แต่ Amit มันใช้งานได้สำหรับฉัน ฉันยินดีถ้าคุณสามารถอธิบายได้ว่าทำไมมันไม่ทำงาน
Hussain KMR Behestee

1
@HussainKMRBehestee คำอธิบาย: ฉันสามารถเดาได้ว่าไวยากรณ์ใน Java บอกว่าเพื่อยกระดับชั้นที่เราต้องเรียกนวกรรมิกและในขณะที่เรียกตัวสร้าง()เป็นภาคบังคับ อย่างไรก็ตาม C, C ++ ไม่ใช่สิ่งที่จำเป็น นี่คือตัวอย่างที่ไม่สามารถใช้งานได้ นอกจากนี้ฉันพบโพสต์นี้ ซึ่งอธิบายเพิ่มเติมเกี่ยวกับไวยากรณ์ใน Java และวิธีการแยกวิเคราะห์ ฉันชอบที่จะเห็นกรณีตัวอย่างเมื่อไวยากรณ์นี้ใช้งานได้สำหรับคุณ
Amit Upadhyay

1
โอ้ความเลวของฉันมันเป็นตัวพิมพ์นอก Outer obj = (new Outer ()). new Inner (); หวังว่าคราวนี้มันโอเคและขอบคุณที่สังเกตว่า
Hussain KMR Behestee

18

ตามที่ระบุไว้ในเอกสาร :

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

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

ขอบคุณ! เพิ่งเริ่มต้น
เบรนแนนมิลเลอร์

10

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

ยกตัวอย่างของคำถามจะทำอย่างไรถ้าZShapeไม่สามารถคงที่ได้เพราะมันต้องการตัวแปรShapeระดับโลก

คุณจะสร้างตัวอย่างใหม่ได้ZShapeอย่างไร นี่คือวิธี:

เพิ่ม getter ในคลาสพาเรนต์:

public ZShape getNewZShape() {
    return new ZShape();
}

เข้าถึงแบบนี้:

Shape ss = new Shape();
ZShape s = ss.getNewZShape();


1

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

public class Shape {

    private String shape;

    public ZShape zShpae;
    public SShape sShape;

    public Shape(){
      int[][] coords =  noShapeCoords;
      shape = "NoShape";
      zShape = new ZShape();
      sShape = new SShape();
    }

    class ZShape{
      int[][] coords =  zShapeCoords;
      String shape = "ZShape";
    }

    class SShape{
      int[][] coords = sShapeCoords;
      String shape = "SShape";
    }

 //etc
}

จากนั้นคุณสามารถรูปร่างใหม่ (); และเยี่ยมชม ZShape ผ่าน shape.zShape;


1
ทางออกที่ผิด ข้อผิดพลาดเชิงตรรกะ หากคลาสภายใน (เช่น ZShape) ต้องการฟิลด์ใด ๆ ให้ตั้งค่าในตัวสร้างคลาสภายนอกคุณต้องรับมัน! รูปร่างสาธารณะ (String field1_innerClass, int field2_innerClass ... ) {zShape = ใหม่ ZShape (String field1_innerClass, int field2_innerClass ... ) ... }}
Mohsen Abasi

1

ไม่จำเป็นต้องทำให้คลาสที่ซ้อนกันเป็นแบบสแตติก แต่ต้องเป็นแบบสาธารณะ

public class Test {
    public static void main(String[] args) {
        Shape shape = new Shape();
        Shape s = shape.new Shape.ZShape();
    }
}

1

สิ่งหนึ่งที่ฉันไม่ได้ตระหนักในตอนแรกเมื่ออ่านคำตอบที่ยอมรับได้คือการทำให้ชั้นในคงที่นั้นเป็นสิ่งเดียวกันกับการย้ายไปยังชั้นเรียนที่แยกต่างหาก

ดังนั้นเมื่อได้รับข้อผิดพลาด

xxx ไม่ใช่คลาสที่ล้อมรอบ

คุณสามารถแก้ไขได้ด้วยวิธีใดวิธีหนึ่งต่อไปนี้:

  • เพิ่มstaticคำหลักให้กับคลาสภายในหรือ
  • ย้ายออกไปยังคลาสแยกต่างหาก

1

ในกรณีที่คลาส Parent เป็น singleton ให้ใช้วิธีดังต่อไปนี้:

Parent.Child childObject = (Parent.getInstance()).new Child();

โดยที่getInstance()จะส่งคืนวัตถุระดับชั้นเดียวของวัตถุ


0

เพื่อให้บรรลุความต้องการจากคำถามเราสามารถนำคลาสเข้าสู่อินเตอร์เฟส:

public interface Shapes {
    class AShape{
    }
    class ZShape{
    }
}

จากนั้นใช้เป็นผู้เขียนทดลองก่อนหน้านี้:

public class Test {
    public static void main(String[] args) {
        Shape s = new Shapes.ZShape();
    }
}

หากเรากำลังมองหาวิธีการแก้ปัญหา "ตรรกะ" ที่เหมาะสมควรใช้fabricรูปแบบการออกแบบ

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