40

我看到很多 java 代码,其中 android 更喜欢让开发人员使用静态内部类。特别是对于自定义 ListAdapters 中的ViewHolder Pattern等模式。

我不确定静态类和非静态类之间有什么区别。我已经阅读过它,但在考虑性能或内存占用时它似乎没有意义。

4

5 回答 5

72

不仅仅是安卓开发者...

非静态内部类始终保持对封闭对象的隐式引用。如果您不需要该参考,它所做的只是消耗内存。考虑一下:

class Outer {
    class NonStaticInner {}
    static class StaticInner {}
    public List<Object> foo(){ 
        return Arrays.asList(
            new NonStaticInner(),
            new StaticInner()); 
    }
}

当你编译它时,你得到的将是这样的:

class Outer {
    Outer(){}
    public List<Object> foo(){ 
        return Arrays.asList(
            new Outer$NonStaticInner(this),
            new StaticInner()); 
    }
}
class Outer$NonStaticInner {
    private final Outer this$0;
    Outer$NonStaticInner(Outer enclosing) { this$0 = enclosing; }
}
class Outer$StaticInner {
    Outer$StaticInner(){}
}
于 2010-06-24T06:19:46.930 回答
26

静态内部类和非静态内部类之间的主要区别在于,非静态内部类可以访问外部类的其他成员,即使它们是私有的。非静态内部类是外部类的“一部分”。如果没有外部类的实例,您将无法创建它们,它们也无法存在。这样做的结果是当外部类的实例被销毁时,非静态内部类的实例也被销毁。

另一方面,静态内部类就像普通的外部类一样。生死自负。您不需要外部类的实例来存在内部类。这意味着它们也有自己的生命周期。当垃圾收集器决定销毁它们时,它们会被销毁。

这对内存和/或性能有何影响?我真的不知道。:)

于 2010-06-24T03:31:04.487 回答
15

静态内部类(即在另一个类中用关键字声明的类static)与“普通”类非常相似,只是您不会污染包的名称空间。这是他们(唯一的)区别和好处,我相信这就是您在 Android 中看到它的原因。

当类的目的与主类紧密相关但不依赖于其实例时,请使用静态内部类。这通常被认为是一种良好的做法。

于 2010-06-24T02:50:49.947 回答
7

非静态内部类实例持有对外部类实例的引用,而静态内部类实例不持有。

这与应用程序的内存占用有关,因为隐藏的引用可能导致内存泄漏 - 垃圾收集器无法收集外部类实例,直到不再存在引用。此外,附加引用本身也需要内存,如果使用大量实例,这可能是相关的。

class Outer{
    class Inner{//Only works with non static inner class
          public Outer getOuter(){return Outer.this;}
    }
}

它也与其使用相关,对外部类的引用是内部类的 ctor 参数,要创建一个新的非静态内部类对象,您必须像外部类的实例上的成员函数一样调用 ctor 或从在外部类的成员函数中。这意味着如果没有外部类的实例,就不能拥有内部类的实例。

Outer.Inner in = new Outer().new Inner();
于 2010-06-24T10:26:28.667 回答
5

如果您反编译一个内部类(或使用调试器观察它),您可以看到生成的代码用于访问用于创建它们的外部类的实例。这样做的开销是更多的内存用于额外的指针,更多的 cpu 用于垃圾收集,因为额外的测试指针,如果你想挑剔,编译时间更长。创建非静态内部类的实例有点复杂,因为您需要外部类的实例来创建它们。

可以控制静态和非静态内部类的可见性。通常,如果它们的实现与外部类的内部细节有很强的联系,那么它们是私有的,并且开发人员认为代码不能被重用。从这个意义上说,它们并不比私有函数好。在像 Map.Entry 这样的情况下,内部类可能是公共的,其中内部类与该类公开的接口强连接,并且开发人员认为没有某种 Map 就可以使用 Map.Entry。这两种类型都可以访问外部类的私有成员,而外部类可以访问内部类的私有成员。

静态和非静态内部类的实例像其他所有类一样被垃圾收集。外部类的抓取收集和内部类的垃圾收集之间没有特殊的联系。

对于像 swing 或 android 这样的 UI 类实现,您会看到静态内部类,因为它们被视为私有函数。这些类不是为了外部类之外的可重用性而开发的,并且与外部类的内部实现密切相关。没有理由公开它们并确保它们可以在比外部类要求的特定上下文更多的情况下工作。

于 2010-06-24T06:22:54.917 回答