【问题标题】:Difference between static nested class and regular class静态嵌套类和普通类的区别
【发布时间】:2015-05-19 20:53:37
【问题描述】:

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

// 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 无法直接访问 ContainingClass.privateStaticField 吗?或者是否还有其他不常讨论或遇到的细微差异?

【问题讨论】:

  • 我无法完全确认,但据我所知,您的问题的答案是:不,没有其他区别。
  • 我可能错了,但我记得在某处读过非静态内部类对外部类有隐式引用,但静态内部类没有。
  • @Naveed,我将不得不做更多的研究。但是,我很确定您正在考虑非静态方法对调用它们的对象具有隐式引用,而静态方法没有说引用,因为它们属于类而不是任何单个实例。换句话说:您可以在非静态方法中使用“this”关键字,但不能在静态方法中使用。

标签: java class


【解决方案1】:

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

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

【讨论】:

  • 我选择这个答案是正确的,因为静态嵌套类除了一些其他顶级类之外,所有额外的“品质”都被赋予,因为它在封闭的范围内类,即使它不是所述封闭类的成员。
  • 一个嵌套的静态类确实是外部类的成员:"一个类体可能包含类成员的声明,即字段(§8.3)、方法(§8.4 )、类 (§8.5) 和接口 (§8.5)。" docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.6"成员类是一个类,其声明直接包含在另一个类或接口声明的主体中 (§ 8.1.6, §9.1.4)。” docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.5
【解决方案2】:

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

您可以选择将 ContainedStaticClass 设为受保护或私有,这不是 OutsideClass 的选项。

【讨论】:

  • 好点。在这种情况下,问题在于谁可以访问这些类,而不是这些类可以访问什么。我必须记住要双向思考。
【解决方案3】:

一个细微的区别是嵌套类可以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
        }
    }
}

但这也与类的范围有关。

【讨论】:

  • 谢谢。这是我正在寻找的好东西。这肯定会让初学者绊倒。
【解决方案4】:

有几个细微的差别。

可能最重要的是可以将嵌套的静态类设为privateprotected。顶级类只能是包私有或public

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

  • 一个嵌套的静态类可以"hide" or "shadow"其他同名的类。当嵌套静态类与外部类同名,并且都在作用域内时,嵌套静态类会隐藏外部类。

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

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

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

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

【讨论】:

    【解决方案5】:

    另一个细微的差别发生在反射用例中。使用Class.forName 加载类所需的类名有点古怪。

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

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

    【讨论】:

      猜你喜欢
      • 2011-02-25
      • 2019-07-14
      • 1970-01-01
      • 2019-07-06
      • 1970-01-01
      • 2010-09-09
      相关资源
      最近更新 更多