不是一个封闭类Java。

412

我正在尝试制作俄罗斯方块游戏,但在创建对象时遇到编译器错误

Shape不是一个封闭类

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

我正在为每个形状使用内部类。这是我的一部分代码。
public class Shapes {
    class AShape {
    }
    class ZShape {
    }
}

我做错了什么?


192
new Shape().new ZShape(); 这段代码需要一个外部实例来实例化 ZShape 类。 - Sotirios Delimanolis
4
将内部类移动到单独的文件中。 - Dimmduh
在这种情况下,@Dimmduh的评论应该是答案。它们不应该是内部类。将它们移动将识别出存在的Shape类的其他问题。 - Jeremiah Adams
不在这里回答问题,但我可以建议在这里使用_继承_,其中AShapeZShape扩展了基类Shapes。嵌套类对于这个问题来说并不是一个很好的设计。 - Paramvir Singh Karwal
12个回答

527

ZShape不是静态的,因此需要外部类的实例。

最简单的解决方案是如果可以的话,使ZShape和任何嵌套类都为static

我还会尽可能使任何字段为finalstatic final


16
ZShape声明为static完全违背了他尝试实例化ZShape的目的。 - Cardano
18
卡尔达诺将其变为“静态”使其更容易,而不是更难。 - Peter Lawrey
13
另一个简单的解决方案是让外部类实例化内部类,即通过以下方式获取ZShape: ZShape myShape = new Shape().instantiateZShape();。这意味着你得到的ZShape没有Shape是不存在的,这也是本意所在。 - Vince
2
如果我们想要静态或实例,有两种情况。将其设置为静态并不总是有帮助的。 - Yogesh Chuahan
2
这里的评论似乎表明人们不理解 Java 中的静态嵌套类。将类设置为静态并不意味着只会有一个实例,它只是意味着 ZShape 不需要存在 Shapes 的实例。 - Mark Rotteveel
显示剩余4条评论

225

假设RetailerProfileModel是您的主类,而RetailerPaymentModel是其中的内部类。您可以按照以下方式在类外创建内部类的对象:

假设RetailerProfileModel是您的主类,而RetailerPaymentModel是其中的内部类。您可以按照以下方式在类外创建内部类的对象:

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

45
这个答案真的很有帮助,我从未知道你可以连续调用两次new(而我已经使用Java 8年以上了!) - PaulBGD
1
你可以随意调用new操作符多次,直到你不想保留该对象的引用为止。 - Vishal Kumar
1
如果以这种方式创建内部类的对象,它将如何访问外部类的成员? - Alpha Huang
1
在内部类中,您可以使用OuterClass.this。但我认为没有办法从内部类的代码外部获取实例。当然,您始终可以引入自己的属性:public OuterClass getOuter() { return OuterClass.this; } - Vishal Kumar
3
虽然这个语法比较复杂,让我感到沮丧,但这应该是被接受的答案。 - Josh M.
显示剩余2条评论

58
我建议不将非静态类转换为静态类,因为在这种情况下,您的内部类无法访问外部类的非静态成员。
示例:
class Outer
{
    class Inner
    {
        //...
    }
}

所以,在这种情况下,你可以做类似于这样的事情:

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

1
Outer.Inner obj = (new Outer).new Inner(); 这段代码的意思是创建了一个外部类Outer的内部类Inner的实例对象obj。 - Hussain KMR Behestee
1
@HussainKMRBehestee,那肯定行不通。但是这个可以:Outer.Inner obj = new Outer().new Inner(); - Amit Upadhyay
但是,阿米特,它对我有效。如果您能解释为什么它不起作用,我会很高兴。 - Hussain KMR Behestee
1
@HussainKMRBehestee,解释:我猜Java语法规定实例化一个类需要调用构造函数,并且在调用构造函数时()是必须的。然而,在C、C++中这不是必须的。这里有一个不起作用的示例。此外,我发现这篇文章更详细地解释了Java语法以及它们如何被解析。我很想看到一个样例,证明这种语法对你有效。 - Amit Upadhyay
1
哦,我的错,那是一个打字错误。Outer.Inner obj = (new Outer()).new Inner(); 希望这次没问题了,感谢你的注意。 - Hussain KMR Behestee

21

根据文档所述:

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

虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅有链接的答案可能会失效。- 来自审查 - Muhammad Omer Aslam
谢谢!刚开始。 - Brennan Miller

10

有时候,我们需要创建一个内部类的新实例,但由于它依赖于父类的一些全局变量,因此不能将其设置为静态。在这种情况下,如果您尝试创建一个非静态的内部类的实例,则会抛出not an enclosing class错误。

以问题为例,如果ZShape不能是静态的,因为它需要Shape类的全局变量,怎么办?

如何创建ZShape的新实例? 这就是方法:

在父类中添加一个getter:

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

像这样访问:

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

9
Shape shape = new Shape();
Shape.ZShape zshape = shape.new ZShape();

3

如果父类是单例模式,请使用以下方式:

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

getInstance()将返回父类单例对象。


1
不需要将嵌套类设为静态,但必须是公共的。
public class Test {
    public static void main(String[] args) {
        Shape shape = new Shape();
        Shape s = shape.new Shape.ZShape();
    }
}

1
为了满足问题的要求,我们可以将类放入接口中:
public interface Shapes {
    class AShape{
    }
    class ZShape{
    }
}

然后像作者之前尝试的那样使用:

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

如果我们正在寻找适当的“逻辑”解决方案,应该使用fabric设计模式。

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
}

然后你可以创建新的形状(Shape)并通过 shape.zShape 访问 ZShape。

1
一个错误的解决方案。逻辑错误。如果内部类(例如ZShape)需要设置任何字段,在外部类的构造函数中必须获取它!public Shape(String field1_innerClass,int field2_innerClass ...){zShape = new ZShape(String field1_innerClass,int field2_innerClass ...)...}} - Mohsen Abasi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接