静态嵌套类和常规类之间的区别

时间:2015-05-19 20:53:37

标签: java class

我知道这是一个重复的问题,但我想以非常具体的方式提出这个问题,以澄清一个非常重要的问题。主要问题是:当一个是静态嵌套类而另一个是常规顶级类而不是访问包含类中的私有静态字段时,其他相同类之间是否存在任何差异?

// ContainingClass.java
public class ContainingClass {
    private static String privateStaticField = "";

    static class ContainedStaticClass {
        public static void main(String[] args) {
            ContainingClass.privateStaticField = "new value";
        }
    }
}

// OutsideClass.java
public class OutsideClass {
    public static void main(String[] args) {
        ContainingClass.privateStaticField = "new value";  // DOES NOT COMPILE!!
    }
}

换句话说:ContainedStaticClass可以访问或执行的内容与OutsideClass可以访问或执行的内容之间的唯一差异,OutsideClass无法访问{{1}直接?或者是否存在其他未经常讨论或遇到的微妙差异?

5 个答案:

答案 0 :(得分:2)

您的陈述是正确的:静态类和外部类之间的唯一区别是访问类和封闭类的成员。 static关键字声明该类不是内部类:它实际上是封闭类范围内的外部类。

请参阅https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.5.1

答案 1 :(得分:2)

ContainedStaticClass具有包私有(即默认)可见性,而OutsideClass具有公共可见性。

您可以选择将ContainedStaticClass设为protected或private,而不是OutsideClass的选项。

答案 2 :(得分:1)

一个细微的区别是嵌套类能够成为封闭类型的shadow成员:

class ContainingClass {
    public static String privateStaticField = "a";

    static class ContainedStaticClass {
        public static String privateStaticField = "b";
        public static void main(String[] args) {
            System.out.println(privateStaticField);  // prints b
        }
    }
}

但这也与班级的范围有关。

答案 3 :(得分:1)

有一些细微的差别。

可能最重要的一个是可以使嵌套的静态类为privateprotected。顶级类只能是程序包专用或public

我能想到的其他差异是技术细节,在那些细节很重要的地方,您可能不应该编写代码:

  • 嵌套的静态类可以"hide" or "shadow"个其他相同名称的类。当嵌套的静态类与外部类具有相同的名称并且都在范围内时,嵌套的静态类将隐藏外部类。

  • 嵌套的静态类是其外部类的子类中的inherited,因此它在这些子类中的范围内,可以在没有完全限定名称或静态导入的情况下进行引用。

  • 同一包中的两个外部类不能共享相同的名称,但是一个类可以继承多个具有相同名称的嵌套静态类(例如,从两个接口)。除非嵌套类的名称为is used ambiguously,否则不会导致编译错误。

  • 由于继承,嵌套的静态类可以具有多个不同的fully-qualified names,例如在class A { static class B extends A {} }中,类A.B可以称为A.B.B,{ {1}},依此类推。外部类只能具有一个完全限定的名称。

  • 外部类的canonical name等于其binary name,但是嵌套的静态类的规范名称不等于其二进制名称。嵌套静态类的二进制名称带有符号A.B.B.B,用于将外部类的二进制名称与嵌套静态类的简单名称分开。

答案 4 :(得分:0)

在反射性用例中还有另一个细微的差异。用Class.forName加载类所需的类名称有点时髦。

Class.forName("com.acme.OuterClass.Innerclass");  // not found
Class.forName("com.acme.OuterClass$Innerclass");  // correct

另请参阅: Instantiate nested static class using Class.forName