Java:静态类 vs 内部类

383

静态嵌套类和非静态嵌套类有什么区别?


Java文档术语:嵌套类分为两种类型:静态和非静态。声明为静态的嵌套类称为静态嵌套类。非静态嵌套类称为内部类。 - sactiw
8个回答

583

一个内部类,根据定义,不能是静态的,因此我将重新阐述你的问题为“静态和非静态嵌套类之间有什么区别?”

非静态嵌套类可以完全访问其所嵌套的类中的成员。 静态嵌套类没有对包含它的类实例的引用,因此它不能调用非静态方法或访问所嵌套的类实例的非静态字段。


3
好的回答。从实例中访问静态成员非常不合逻辑。应该只能通过SomeClass.StaticMember或在SomeClass内部通过StaticMember(而不是this.StaticMember)访问静态成员,这样我们就不会遇到这些问题了。 - flying sheep
6
当你说“静态嵌套类无法调用其所嵌套的类的非静态方法或访问非静态字段。”时,这意味着不创建封闭类的对象,对吗?因为我认为,嵌套的静态类在行为上就像一个嵌套在另一个顶级类中以方便打包的顶级类。因此,应该可以通过一个对象访问非静态成员。 - Shatu

142
让我们看一下智慧的源泉来解决这样的问题: Joshua Bloch 的 Effective Java
从技术上讲,没有静态内部类这样的东西。根据 Effective Java,正确的术语是静态嵌套类。非静态嵌套类确实是一个内部类,以及匿名类和本地类。
现在引用一下:
每个非静态嵌套类的实例都与其包含类的一个封闭实例隐式关联...可以调用包含实例上的方法。
静态嵌套类不具有访问封闭实例的权限。它也使用较少的空间。

16
我正在阅读该内容。第22条:静态成员类优于非静态成员类。 - Raymond Chenon
5
Bloch指出,在不必要的非静态内部类中引用封闭实例可能会防止垃圾回收,这点需要注意。 - Carl Pritchett
2
何时使用其中一个而不是另一个? - IgorGanapolsky
1
根据《Java语言规范》,不存在静态内部类这样的东西。Bloch的书可能很好,但JLS是唯一的规范参考。 - user207421
4
阅读这个答案中的引言,我并没有看到它与JLS相矛盾。相反,它似乎证实了JLS。 - the_new_mr
@the_new_mr 当然。重点是你应该优先选择原始来源而不是其他来源。 - user207421

75

静态内部类和非静态内部类有两种不同之处。

  1. 在声明成员字段和方法的情况下,非静态内部类不能具有静态字段和方法。 但是,在静态内部类的情况下,可以具有静态和非静态字段和方法。

  2. 非静态内部类的实例是通过外部类对象的引用创建的,它所定义的外部类具有封闭实例。但是,静态内部类的实例是在没有Outer类的引用的情况下创建的,这意味着它没有封闭实例。

看这个例子

class A
{
    class B
    {
        // static int x; not allowed here
    }

    static class C
    {
        static int x; // allowed here
    }
}

class Test
{
    public static void main(String… str)
    {
        A a = new A();

        // Non-Static Inner Class
        // Requires enclosing instance
        A.B obj1 = a.new B(); 

        // Static Inner Class
        // No need for reference of object to the outer class
        A.C obj2 = new A.C(); 
    }
}

由于其中一个不存在,因此它们之间的差异是无限的。 - user207421
7
例子确实有帮助 =) - Micro
在一个示例中解决了静态和非静态的两个疑问,非常整洁! - user3833732

18
  1. 静态内部类无法访问外部类的非静态成员。它可以直接访问外部类的静态成员(实例字段和方法),与过程式获取值而不创建对象的样式相同。

  2. 静态内部类可以声明静态和非静态成员。静态方法可以访问主类的静态成员。但是,它无法访问非静态内部类的成员。要访问非静态内部类的成员,必须创建非静态内部类的对象。

  3. 非静态内部类无法声明静态字段和静态方法。它必须在静态或顶层类型中声明。这样做会导致错误,提示“只能在静态或顶层类型中声明静态字段”。

  4. 非静态内部类可以以过程式样式获取值来访问外部类的静态和非静态成员,但无法访问静态内部类的成员。

  5. 在创建内部类对象之前,封闭类无法访问内部类的成员。如果主类正在访问非静态类的成员,则可以创建非静态内部类的对象。

  6. 如果主类要访问静态内部类的成员,将有两种情况:

    • 情况1:对于静态成员,可以使用静态内部类的类名
    • 情况2:对于非静态成员,可以创建静态内部类的实例。

1
请问您能否修正类似“IF main class in accessing members of non-static class”或者“if main class in accessing members of static inner class”这样的语法错误?我并不明白您想要表达什么。 - nhahtdh

11

讨论嵌套类...

区别在于,也是静态的嵌套类声明可以在封闭类之外实例化。

当您有一个非静态的嵌套类声明时,Java不允许您除了通过封闭类以外的方式进行实例化。由内部类创建的对象与由外部类创建的对象相关联,因此内部类可以引用外部的字段。

但如果它是静态的,则链接不存在,无法访问外部字段(除了通过像任何其他对象一样的普通引用),因此可以单独实例化嵌套类。


3

静态内部类:可以声明静态成员和非静态成员,但只能访问其父类的静态成员。

非静态内部类:只能声明非静态成员,但可以访问其父类的静态和非静态成员。


3
不存在"静态内部类",而(非静态的)内部类可以声明某种类型的静态成员。根据[JLS 8.1.3](http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.3 "Inner Classes and Enclosing Instances"):“内部类是一个嵌套类,没有明确或隐式地声明为静态。[...]内部类可能不会声明静态成员,除非它们是编译时常量字段(§15.28)。 - user85421

3
一个内部类不能是静态的,因此我会将您的问题重新表述为“静态和非静态嵌套类之间有什么区别?”。
正如您所说,内部类不能是静态的...我发现下面的代码被赋予了静态属性....原因是什么?哪个是正确的....
是的,静态嵌套类型的语义中没有任何东西会阻止您这样做。这段代码可以正常运行。
    public class MultipleInner {
        static class Inner {
        }   
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Inner();
        }
    }
}

这是在该网站上发布的一段代码...

对于问题 ---> 静态嵌套类可以多次实例化吗?

答案是 --->

当然,嵌套类型可以进行自己的实例控制(如:私有构造函数、单例模式等),但这与它是嵌套类型无关。另外,如果嵌套类型是静态枚举,则根本不能实例化它。

但总的来说,是的,静态嵌套类型可以多次实例化。

请注意,从技术上讲,静态嵌套类型不是“内部”类型。


2
一个静态嵌套类与其外部类(和其他类)的实例成员交互,就像任何其他顶级类一样。实际上,静态嵌套类在行为上是一个被嵌套在另一个顶级类中以方便打包的顶级类。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接