【问题标题】:Why does Android prefer static classes为什么Android更喜欢静态类
【发布时间】:2011-03-07 14:54:19
【问题描述】:

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

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

【问题讨论】:

    标签: java android performance static-classes


    【解决方案1】:

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

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

    【讨论】:

    • 您能否详细介绍一下静态内部类以及内部类的构成?这很有趣
    【解决方案2】:

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

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

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

    【讨论】:

    • “这对内存和/或性能有何影响?”它将防止内存泄漏。拥有静态内部类会阻止它引用 Activity / Fragment,因为静态内部类无法访问外部成员变量。如果我们在 Activity 上存在内存泄漏,并且该 Activity 保留了许多重对象(如 Views)的引用,它将消耗不必要的内存并降低性能。
    【解决方案3】:

    不仅仅是 Android 开发者...

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

    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(){}
    }
    

    【讨论】:

    • 确实如此,但还有更多 - 有时您没有对外部类的引用,但仍想实例化内部类(如果它是可见的)。
    • +1 表示编译器将从输入源中得到的印象
    • 非静态内部类不能显式声明对外部的引用(只需要手动实例化它),从而实现两全​​其美:没有静态内存成本的外部引用?此外,不是静态内部类不可重入,因此仅在需要它的单个实例的情况下才有用?
    【解决方案4】:

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

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

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

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

    【讨论】:

      【解决方案5】:

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

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

      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();
      

      【讨论】:

        猜你喜欢
        • 2015-08-06
        • 1970-01-01
        • 2011-02-12
        • 1970-01-01
        • 2015-12-25
        • 2011-11-16
        • 2011-10-20
        • 2015-08-13
        • 1970-01-01
        相关资源
        最近更新 更多