Java中的静态嵌套类,为什么?

Dav*_*ner 208 java static class member

我正在查看Java代码,LinkedList并注意到它使用了静态嵌套类Entry.

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

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

}
Run Code Online (Sandbox Code Playgroud)

使用静态嵌套类而不是普通内部类的原因是什么?

我能想到的唯一原因是,Entry无法访问实例变量,因此从OOP的角度来看,它具有更好的封装.

但我认为可能有其他原因,也许是表现.可能是什么?

注意.我希望我的条款正确,我会称之为静态内部类,但我认为这是错误的:http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html

mat*_*t b 265

您链接到的Sun页面在两者之间存在一些关键差异:

嵌套类是其封闭类的成员.非静态嵌套类(内部类)可以访问封闭类的其他成员,即使它们被声明为私有.静态嵌套类无权访问封闭类的其他成员.
...

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

有没有必要LinkedList.Entry成为顶级类,因为它是唯一使用的LinkedList(也有一些其他接口也有一个名为静态嵌套类Entry,如Map.Entry-同一个概念).而且由于它不需要访问LinkedList的成员,因此它是静态的 - 它是一种更清晰的方法.

正如Jon Skeet指出的那样,我认为如果你使用嵌套类是一个更好的主意,那就是从静态开始,然后根据你的用法确定它是否真的需要非静态.


Jon*_*eet 45

在我看来,每当你看到一个内部类时,问题应该是另一种方式 - 它是否真的需要是一个内部类,具有额外的复杂性和对实例的隐式(而不是明确和更清晰的,IMO)引用包含类?

请注意,我有偏见作为C#粉丝 - 虽然它确实有嵌套类型,但C#没有内部类的等价物.我不能说我错过了内部课程:)

  • 我可能是错的,但这看起来像一个静态嵌套类的例子,而不是内部类.他们甚至在示例中指定他们无法访问嵌套类中周围类的实例变量. (4认同)
  • @nawfal:是的,除了一些小问题,我对C#语言设计(和指定)的表现感到敬畏. (3认同)
  • 嵌套类型是C#与Java相比非常正确的领域之一.我总是惊叹于它的语义/逻辑正确性. (2认同)

Lei*_*igh 26

这里需要考虑非显而易见的内存保留问题.由于非静态内部类维护对其"外部"类的隐式引用,因此如果强引用内部类的实例,则外部实例也被强引用.当外部类没有被垃圾收集时,这可能会导致一些令人头疼的问题,即使看起来没有任何东西引用它.


小智 10

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

作为一项规则,我想说,如果你定义一个基本上作为数据成员集合的类,比如C中的"struct",可以考虑将其设置为静态.


use*_*551 7

静态嵌套类与任何其他外部类一样,因为它无权访问外部类成员.

为了方便包装,我们可以将静态嵌套类添加到一个外部类中以便于阅读.除此之外,没有静态嵌套类的其他用例.

这种用法的示例,您可以在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;
    }
}
Run Code Online (Sandbox Code Playgroud)


see*_*gan 7

静态内部类用于构建器模式.静态内部类可以实例化它的外部类,它只有私有构造函数.因此,您可以使用静态内部类来实例化仅具有私有构造函数的外部类.你不能对内部类做同样的事情,因为你需要在访问内部类之前创建外部类的对象.

class OuterClass {
    private OuterClass(int x) {
        System.out.println("x: " + x);
    }

    static class InnerClass {
        public static void test() {
            OuterClass outer = new OuterClass(1);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass.test();
        // OuterClass outer = new OuterClass(1); // It is not possible to create outer instance from outside.
    }
}
Run Code Online (Sandbox Code Playgroud)

这将输出x:1


Joh*_*n29 6

来自http://docs.oracle.com/javase/tutorial/java/javaOO/whentouse.html:

如果需要访问封闭实例的非公共字段和方法,请使用非静态嵌套类(或内部类).如果不需要此访问权限,请使用静态嵌套类.