【问题标题】:Why nested classes behave differently between Java and C#?为什么嵌套类在 Java 和 C# 之间的行为不同?
【发布时间】:2015-05-22 05:06:42
【问题描述】:

我不明白为什么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);
    }
}

错误出现在public static final TestClass CONSTANT = new InnerClass(5); 部分。 错误是:

I:\Documents\NetBeansProjects\TestingGround\src\testingground\TestClass.java:22: 错误:非静态变量不能从静态引用 context public static final TestClass CONSTANT = new InnerClass(5); ^ I:\Documents\NetBeansProjects\TestingGround\src\testingground\TestClass.java:22: 错误:内部类 TestClass.InnerClass 中的非法静态声明 public static final TestClass CONSTANT = new 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 不允许这样做?

【问题讨论】:

  • 我已经更新了标题...不幸的是,这使得这个问题与许多类似的问题重复了一次bing.com/…...但 Jon Skeet 回答的并不多 - 所以让我们再找一个 :) 随意改写标题以更好地反映您的问题。
  • @AlexeiLevenkov 没有一个“重复”解决这个特定问题。一个问题是为什么 C# 嵌套类不能像 Java 内部类那样访问其外部类的内部。有人问 Java 静态类和 C# 静态类有什么区别,但从这个问题的给定答案来看,这是一个认知上的飞跃。

标签: java c#


【解决方案1】:

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

选项 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

只需将InnerClass设为静态:

public static final class InnerClass extends TestClass

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

【讨论】:

  • 如果允许,我会在 4 分钟内接受。我不知道可以在 Java 中实例化静态类,因为我更习惯于 C#。 (无论如何,这些不是我的类的实际名称,为了演示,我简化了我的类。)我知道泛型会以不同的方式应用,Java 使用类型擦除而不是 C# 的任何技术,但无论如何感谢您的提醒。大多数语言出于各种原因倾向于以不同的方式对待泛型。
【解决方案2】:

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

【讨论】:

  • 这基本上是对第二个错误的改写,因此没有帮助。
  • @Pharap:嗯,这是对第二个错误的来源的解释,并参考了 JLS。这不是一个完整的解释,但我不会说它“没有帮助”。
  • @JonSkeet 除了它没有帮助之外,只是复制和粘贴 JLS 的一部分而无需进一步阐述,无论问题多么简单或复杂,都不是一个很好的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-20
  • 1970-01-01
相关资源
最近更新 更多