我查看了LinkedList的Java代码,注意到它使用了一个静态嵌套类Entry。

public class LinkedList<E> ... {
...

 private static class Entry<E> { ... }

}

为什么要使用静态嵌套类,而不是普通的内部类?

我能想到的唯一原因是,Entry不能访问实例变量,所以从OOP的角度来看,它有更好的封装。

但我想可能还有其他原因,可能是表现。可能是什么?

请注意。我希望我的术语是正确的,我将它称为静态内部类,但我认为这是错误的:http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html


当前回答

在我看来,当你看到一个内部类时,问题应该是反过来的——它真的需要是一个内部类吗?它有额外的复杂性和隐式(而不是显式和更清晰的)引用包含类的实例?

请注意,作为一个c#爱好者,我有偏见——c#没有等价的内部类,尽管它有嵌套类型。我还不能说我错过了内部类:)

其他回答

我不知道性能上的差异,但正如你所说,静态嵌套类不是外围类实例的一部分。创建一个静态嵌套类似乎更简单,除非你真的需要它是一个内部类。

这有点像为什么在Java中我总是让我的变量是final的——如果它们不是final的,我知道它们有一些有趣的事情发生了。如果使用内部类而不是静态嵌套类,应该有一个很好的理由。

首先,非静态内部类有一个额外的隐藏字段,指向外部类的实例。因此,如果Entry类不是静态的,那么除了拥有它不需要的访问之外,它将携带四个而不是三个指针。

作为一个规则,我想说,如果你定义了一个类,基本上是作为数据成员的集合,就像C中的“struct”,考虑让它静态。

静态嵌套类就像任何其他外部类一样,因为它不能访问外部类成员。

为了方便打包,我们可以将静态嵌套类合并到一个外部类中以提高可读性。除此之外,静态嵌套类没有其他用例。

这种用法的例子,你可以在Android R.java(资源)文件中找到。 android的Res文件夹包含布局(包含屏幕设计),可绘制文件夹(包含用于项目的图像),值文件夹(包含字符串常量)等。

因为所有的文件夹都是Res文件夹的一部分,android工具生成一个R.java(资源)文件,其中内部包含许多静态嵌套类的每个内部文件夹。

下面是在android中生成的R.java文件的外观和感觉: 这里他们只是为了包装方便而使用。

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.techpalle.b17_testthird;

public final class R {
    public static final class drawable {
        public static final int ic_launcher=0x7f020000;
    }
    public static final class layout {
        public static final int activity_main=0x7f030000;
    }
    public static final class menu {
        public static final int main=0x7f070000;
    }
    public static final class string {
        public static final int action_settings=0x7f050001;
        public static final int app_name=0x7f050000;
        public static final int hello_world=0x7f050002;
    }
}

这里有一些不明显的内存保留问题需要考虑。由于非静态内部类维护对其“外部”类的隐式引用,如果内部类的一个实例被强引用,那么外部实例也会被强引用。当外部类没有被垃圾收集时,这可能会导致一些令人费解的问题,即使看起来没有任何东西引用它。

JVM knows no nested classes. Nesting is just syntactic sugar. Below images shows Java file: Below images show class files representation of the java file : Notice that 2 class files are generated, one for parent and another for nested class. Non-static nested class' objects have access to the enclosing scope. That access to the enclosing scope is maintained by holding an implicit reference of the enclosing scope object in the nested object Nested class is a way to represent the intent that the nested class type represents a component of the parent class. public class Message { private MessageType messageType; // component of parent class public enum MessageType { SENT, RECEIVE; } } class Otherclass { public boolean isSent(Message message) { if (message.getMessageType() == MessageType.SENT) { // accessible at other places as well return true; } return false; } } private static nested class represents Point#3 & the fact the nested type can only be the subcomponent to the parent class. It can't be used separately. public class Message { private Content content; // Component of message class private static class Content { // can only be a component of message class private String body; private int sentBy; public String getBody() { return body; } public int getSentBy() { return sentBy; } } } class Message2 { private Message.Content content; // Not possible } More details here.