为什么Java和C#之间的嵌套类行为不同?

为什么Java和C#之间的嵌套类行为不同?,java,c#,Java,C#,我不明白为什么Java中会出现以下代码错误: public abstract class TestClass { private final int data; protected TestClass(int data) { this.data = data; } public final class InnerClass extends TestClass { private InnerClass(int data) { super(data); }

我不明白为什么Java中会出现以下代码错误:

public abstract class TestClass
{
    private final int data;

    protected TestClass(int data) { this.data = data; }

    public final class InnerClass extends TestClass
    {
    private InnerClass(int data) { super(data); }

    public static final TestClass CONSTANT = new InnerClass(5);
    }
}
错误出现在
公共静态最终测试类常量=新的内部类(5)上零件。
错误是:

I:\Documents\NetBeansProjects\TestingGround\src\TestingGround\TestClass.java:22: 错误:非静态变量无法从静态变量引用此变量 上下文公共静态最终测试类常量=新的内部类(5); ^I:\Documents\NetBeansProjects\TestingGround\src\TestingGround\TestClass.java:22: 错误:内部类TestClass.InnerClass中的静态声明非法 公共静态最终测试类常量=新的内部类(5); ^修饰符“static”仅在常量变量声明中允许2个错误

如果我尝试在C#中实现同样的效果,它会很好

public abstract class TestClass
{
    private readonly int data;

    protected TestClass(int data) { this.data = data; }

    public sealed class InnerClass : TestClass
    {
        private InnerClass(int data) : base(data) { }

        public static readonly TestClass CONSTANT = new InnerClass(5);
    }
}
为什么Java不允许这样做?

要创建一个(相对于嵌套的静态类),您需要一个封闭类的实例——在这种情况下您没有实例。注意,C#中没有内部类的直接等价物——C#中的嵌套类更像是Java中的嵌套静态类,C#中类声明中的
static
的含义与Java中类声明中的
static
的含义完全不同

选项1

如果您确实希望它是一个内部类,您可以编写:

public static final TestClass CONSTANT = new SomeConcreteTestClass().new InnerClass(5);
(其中
SomeConcreteTestClass
是扩展
TestClass
的具体类)

或者,可怕的是:

public static final TestClass CONSTANT = ((TestClass) null).new InnerClass(5);
请注意,您需要将声明移出
InnerClass
,因为除了编译时常量表达式之外,内部类不能声明静态变量:

如果内部类声明的成员是显式或隐式静态的,则这是编译时错误,除非该成员是常量变量(§4.12.4)

所以你最终会得到:

public abstract class TestClass
{
    private final int data;

    protected TestClass(int data) { this.data = data; }

    public final class InnerClass extends TestClass
    {
        private InnerClass(int data) { super(data); }        
    }
    public static final TestClass CONSTANT = ((TestClass) null).new InnerClass(5);
}
选项2

只需将
内部类
设置为静态:

public static final class InnerClass extends TestClass

添加
static
是唯一需要的更改。现在,这更像是一个C#嵌套类(尽管泛型的行为总是不同的…),理想情况下,此时您应该重命名该类,因为它不是一个内部类…

Java语言不允许内部类声明显式或隐式静态的成员,除非该成员是一个常量变量,请参阅JLS 8.1.3

如果允许,我将在4分钟内接受。我不知道在Java中实例化静态类是可能的,因为我更习惯于C。(无论如何,这些不是我类的实际名称,为了演示,我简化了我的类。)我知道泛型会有不同的应用,Java使用类型擦除而不是C#的任何技术,但无论如何,感谢您的指导。由于各种原因,大多数语言倾向于以不同的方式对待泛型。这基本上是对第二个错误的重写,因此没有帮助。@Pharap:嗯,这是对第二个错误来源的解释,并参考了JLS。这不是一个完整的解释,但我不会说它“没有帮助”。@JonSkeet除了没有帮助之外,只是复制和粘贴JLS的一部分而没有进一步的阐述并不能得到一个很好的答案,无论问题是多么简单或复杂。我已经更新了标题。。。不幸的是,这使得这个问题重复了许多类似的问题。。。但Jon Skeet的回答并不多,所以让我们再来一个:)请随意改写标题,以更好地反映您的问题。@AlexeiLevenkov没有一个“重复”解决了这个问题。有人会问,为什么C#嵌套类不能像Java内部类那样访问外部类的内部。有人问Java静态类和C#静态类之间有什么区别,但从这个问题的给定答案来看,这是一个认知上的飞跃。