2011-11-03 59 views
2

以下两种情况似乎工作:内部类和字符串在Java中

public class A { 
    private class B { 
     public static final String str = "str"; 
    } 
} 

public class A { 
    private static class B { 
     public static final String str = new String("str"); 
    } 
} 

但是下面给出在评论中指定的错误:

public class A {  
    private class B { 
    //The field str cannot be declared static; 
    //static fields can only be declared in static or top level types 
     public static final String str = new String("str"); 
    } 
} 

为什么它被允许在前面两种情况以及为什么它会导致上一个问题?

回答

4

这是JLS, section 8.1.3要求的。我从来没有看到它的原因,但我怀疑一个不是静态的内部类需要一个外部类的实例,但是声明作为静态破坏了这个概念,并且允许它们会创建一整套其他规则来处理只是这种情况,这被认为是不值得的。而当它是静态的,它就像任何其他类一样,恰好在同一个源文件中。

1

我猜这个限制是由于new String("str")是如何实现的。使用字符串初始化成员可以使用常量池中的条目来完成,但new String("str")需要实际的代码执行,因此必须使用静态init方法中的实际字节码完成此操作。

螺旋式的内部类方案让我头痛,只是想着它(它实际上是内部的kludge),所以我不能解释到底是什么问题,但我怀疑静态init方法运行在不适当的时间如上所述,所以或者结果不可靠,或者系统将无法处理由静态初始化方法中的错误导致的异常。

+0

它不仅仅是'new String(...)'。它是任何不是编译时常量表达式的*初始值设定项。 –

+0

对。 'new String(“literal”)'可能被编译器认为是“安全的”并且被允许,但是这样你就没有必要的通用规则。 –

0

JLS明确规定了这一限制;看到伊斋的回答。

“为什么”的一种可能的解释是,会有一个期望,即非常量静态初始化表达式可以引用封闭类中的静态或非静态。第一个可能会导致类(静态)初始化的排序中的概念或实现困难。第二个是不能实现的,并且会导致难以理解的编译错误。 (考虑新手以简单的方法在静态/非静态访问限制方面经常出现的频率。)

我认为他们只是简单地采取了简单的路线并且禁止了这一点。 (KISS为我工作......)他们可能认为他们可以在稍后的修订中放宽限制,但是之后没有看到需要这样做。