Không phải là một lớp Java kèm theo


366

Tôi đang cố gắng tạo một trò chơi Tetris và tôi đang gặp lỗi trình biên dịch

Shape is not an enclosing class

khi tôi cố gắng tạo một đối tượng

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

Tôi đang sử dụng các lớp bên trong cho mỗi hình dạng. Đây là một phần của mã của tôi

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

Tôi đang làm gì sai?


160
new Shape().new ZShape();. Lớp ZShapecần một cá thể kèm theo để được khởi tạo.
Sotirios Delimanolis

4
di chuyển lớp bên trong sang tập tin riêng
Dimmduh

Bình luận @Dimmduh nên là câu trả lời trong trường hợp này. Họ không nên là lớp học bên trong. Di chuyển chúng sẽ xác định các vấn đề khác với lớp Shape tồn tại.
Jeremiah Adams

Không trả lời câu hỏi ở đây nhưng tôi có thể đề nghị sử dụng tính kế thừa ở đây không AShapeZShapemở rộng lớp cơ sở Shapes. Các lớp lồng không phải là một thiết kế thực sự tốt cho vấn đề này.
Paramvir Singh Karwal

Câu trả lời:


492

ZShape không tĩnh nên nó yêu cầu một thể hiện của lớp bên ngoài.

Giải pháp đơn giản nhất là tạo ZShape và bất kỳ lớp lồng nhau nào staticnếu bạn có thể.

Tôi cũng sẽ làm bất kỳ lĩnh vực nào finalhoặc static finalbạn cũng có thể.


13
Làm cho ZShape statichoàn toàn đánh bại mục đích của những gì anh ta đang cố gắng làm, đó là khởi tạo một bản sao của ZShape.
Cardano

17
@Cardano làm staticcho nó dễ dàng hơn, không khó hơn.
Peter Lawrey

12
một giải pháp đơn giản khác là làm cho lớp kèm theo khởi tạo lớp bên trong, tức là lấy ZShape theo cách này : ZShape myShape = new Shape().instantiateZShape();. Nó ngụ ý ZShape mà bạn nhận được không tồn tại mà không có Hình dạng, đó là mục đích ở đây.
Vince

@Peter Lawrey Làm thế nào bạn nhận ra rằng tất cả các phiên bản Shape phải sử dụng cùng một ZShape? Tôi không nhận được nó từ nguồn của anh ấy.
Không thể tin được vào ngày

2
Có 2 trường hợp nếu chúng ta muốn tĩnh hoặc một thể hiện. Làm cho nó tĩnh sẽ không luôn luôn giúp đỡ.
Yogesh Chuahan

177

Giả sử RetailerProfileModel là lớp chính của bạn và RetailerPaymentModel là một lớp bên trong nó. Bạn có thể tạo một đối tượng của lớp bên trong bên ngoài lớp như sau:

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

34
Câu trả lời này thực sự hữu ích, tôi chưa bao giờ biết bạn có thể gọi mới hai lần liên tiếp (và tôi đã thực hiện java được hơn 8 năm!)
PaulBGD

1
Bạn chắc chắn có thể gọi toán tử mới bất kỳ số lần nào cho đến khi bạn không muốn giữ một tham chiếu về đối tượng đó.
Vishal Kumar

1
Nếu một đối tượng của lớp bên trong được tạo theo cách này, làm thế nào để nó truy cập vào các thành viên của lớp bên ngoài?
Xingang Huang

1
Trong chính lớp bên trong, bạn có thể sử dụng OuterClass.this. Tôi không nghĩ có cách nào để lấy cá thể từ bên ngoài mã của lớp bên trong. Tất nhiên, bạn luôn có thể giới thiệu tài sản của riêng mình: công khai OuterClass getOuter () {return OuterClass.this; }
Vishal Kumar

Hoạt động cho các bài kiểm tra:underTest = Mockito.mock(Outer.class).new InnerNonStaticClass();
felvhage

48

Điều tôi muốn đề xuất là không chuyển đổi lớp không tĩnh thành lớp tĩnh vì trong trường hợp đó, lớp bên trong của bạn không thể truy cập vào các thành viên không tĩnh của lớp bên ngoài.

Thí dụ :

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

Vì vậy, trong trường hợp như vậy, bạn có thể làm một cái gì đó như:

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

Điều gì về Outer.Inner obj = (new Outer) .new Inside ();
Hussain KMR

1
@HussainKMRBehestee, không có gì là không chắc chắn. Tuy nhiên, điều này sẽ hoạt độngOuter.Inner obj = new Outer().new Inner();
Amit Upadhyay

Nhưng Amit, nó làm việc cho tôi. Tôi rất vui nếu bạn có thể giải thích tại sao nó không hoạt động.
Hussain KMR

1
@HussainKMRBehestee, giải thích: Tôi chỉ có thể đoán rằng ngữ pháp trong Java nói rằng để khởi tạo một lớp chúng ta cần gọi hàm tạo, và trong khi gọi hàm tạo ()là bắt buộc. Tuy nhiên, C, C ++ thì không bắt buộc. Đây là một ví dụ không hoạt động. Hơn nữa, tôi tìm thấy bài viết này . đó là giải thích thêm về ngữ pháp trong Java và cách chúng được phân tích cú pháp. Tôi rất thích xem một trường hợp mẫu khi cú pháp này làm việc cho bạn.
Amit Upadhyay

1
Ôi, xấu của tôi, đó là một lỗi đánh máy, Outer.Inner obj = (new Outer ()). New Inside (); hy vọng lần này là ok và cảm ơn vì đã nhận ra điều đó.
Hussain KMR

18

Như đã nêu trong các tài liệu :

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

Mặc dù liên kết này có thể trả lời câu hỏi, tốt hơn là bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi. - Từ đánh giá
Muhammad Omer Aslam

Cảm ơn! Chỉ mới vừa bắt đầu.
Brennan Miller

10

Đôi khi, chúng ta cần tạo một thể hiện mới của một lớp bên trong không thể tĩnh bởi vì nó phụ thuộc vào một số biến toàn cục của lớp cha. Trong tình huống đó, nếu bạn cố gắng tạo thể hiện của một lớp bên trong không tĩnh, sẽ not an enclosing classxảy ra lỗi.

Lấy ví dụ về câu hỏi, nếu ZShapekhông thể tĩnh vì nó cần biến toàn cục của Shapelớp thì sao?

Làm thế nào bạn có thể tạo phiên bản mới của ZShape? Đây là cách:

Thêm một getter trong lớp cha:

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

Truy cập nó như thế này:

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


1

Tôi đã gặp vấn đề tương tự. Tôi đã giải quyết bằng cách tạo một thể hiện cho mọi Lớp công khai bên trong. đối với tình huống của bạn, tôi đề nghị bạn sử dụng kế thừa khác với các lớp bên trong.

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
}

sau đó bạn có thể Shape mới (); và truy cập ZShape thông qua shape.zShape;


1
Một giải pháp sai. Lỗi logic. Nếu lớp bên trong (ví dụ ZShape) yêu cầu bất kỳ trường nào được đặt, trong hàm tạo của lớp bên ngoài, bạn phải lấy nó! Hình dạng công khai (Chuỗi trường1_innerClass, int field2_innerClass ...) {zShape = new ZShape (Chuỗi trường1_innerClass, int field2_innerClass ...) ...}}
Mohsen Abasi

1

Không cần phải làm cho lớp lồng nhau thành tĩnh nhưng nó phải được công khai

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

1

Một điều tôi đã không nhận ra lúc đầu khi đọc câu trả lời được chấp nhận là việc tạo một lớp tĩnh bên trong về cơ bản giống như việc chuyển nó sang lớp riêng của nó.

Như vậy, khi gặp lỗi

xxx không phải là một lớp học kèm theo

Bạn có thể giải quyết nó theo một trong các cách sau:

  • Thêm statictừ khóa vào lớp bên trong, hoặc
  • Di chuyển nó ra lớp riêng của nó.

1

Trong trường hợp nếu lớp Parent là singleton, hãy sử dụng cách sau:

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

nơi getInstance()sẽ trả về đối tượng singleton lớp cha.


0

Để đạt được yêu cầu từ câu hỏi, chúng ta có thể đặt các lớp vào giao diện:

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

và sau đó sử dụng như tác giả đã thử trước đây:

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

Nếu chúng ta tìm kiếm giải pháp "hợp lý", nên sử dụng fabricmẫu thiết kế

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.