Java枚举是否在Android Runtime中分配堆内存?

时间:2018-11-16 20:29:45

标签: java android memory enums heap

我正在观看两位Android工程师的视频,他们谈论Android中的垃圾回收。在引言中,他们对枚举有一点玩笑。罗曼·盖伊(Romain Guy)说:“我必须在那儿纠正你。枚举,他们没有分配。这就是重点。”起初,我以为Romain只是在开玩笑,因为枚举在其他语言中是这样工作的。但是在此之后,切特似乎承认确实没有枚举该枚举,而是做了一些与内存相关的事情(暗示:生活在栈上)。这种反应使我感到困惑。

https://youtu.be/Zc4JP8kNGmQ?t=96

据我所知,从内存的角度来看,Java中的枚举基本上是类实例和seeing as Enum implements Object的固定集合以及对象实例化,因此将被分配给堆。

但是我可以想象,由于编译器可以利用枚举的强大属性,枚举具有某些特殊的状态。类似地,我知道String有多种优化方式,例如文字共享池。

我目前处于固定对象列表中,这些对象在应用程序中用作常量。因此,我可以将其实现为枚举或类实例化数组。假设可读性不是问题,那么做前者会不会表现得更好?

1 个答案:

答案 0 :(得分:3)

枚举是对象。像所有对象一样,它们生活在堆中。

的确,如果您反编译一个简单的枚举,例如:

enum Foo { A, B }

它看起来像这样(省略了一些东西):

  static {};
    Code:
       0: new           #4                  // class Foo
       3: dup
       4: ldc           #7                  // String A
       6: iconst_0
       7: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      10: putstatic     #9                  // Field A:LFoo;
      13: new           #4                  // class Foo
      16: dup
      17: ldc           #10                 // String B
      19: iconst_1
      20: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      23: putstatic     #11                 // Field B:LFoo;
      26: iconst_2
      27: anewarray     #4                  // class Foo
      30: dup
      31: iconst_0
      32: getstatic     #9                  // Field A:LFoo;
      35: aastore
      36: dup
      37: iconst_1
      38: getstatic     #11                 // Field B:LFoo;
      41: aastore
      42: putstatic     #1                  // Field $VALUES:[LFoo;
      45: return

基本上与这样的类相同:

class Bar {
  static final Bar A = new Bar("A");
  static final Bar B = new Bar("B");

  static final Bar[] $VALUES;

  static {
    Bar[] array = new Bar[2];
    array[0] = A;
    array[1] = B;
    $VALUES = array;
  }

  private Bar(String name) {}
}

反编译为:

  static {};
    Code:
       0: new           #2                  // class Bar
       3: dup
       4: ldc           #3                  // String A
       6: invokespecial #4                  // Method "<init>":(Ljava/lang/String;)V
       9: putstatic     #5                  // Field A:LBar;
      12: new           #2                  // class Bar
      15: dup
      16: ldc           #6                  // String B
      18: invokespecial #4                  // Method "<init>":(Ljava/lang/String;)V
      21: putstatic     #7                  // Field B:LBar;
      24: iconst_2
      25: anewarray     #2                  // class Bar
      28: astore_0
      29: aload_0
      30: iconst_0
      31: getstatic     #5                  // Field A:LBar;
      34: aastore
      35: aload_0
      36: iconst_1
      37: getstatic     #7                  // Field B:LBar;
      40: aastore
      41: aload_0
      42: putstatic     #8                  // Field $VALUES:[LBar;
      45: return

从枚举中可以得到一些其他特殊的东西(例如保证它们不能被反射地产生);但实际上,它们只是常规对象。

我认为他们要提出的观点是,枚举不会被多次分配(如果您确实需要单例,则这是实现singetons的好方法)。因此,您需要支付少量的固定费用来加载枚举类。但是您可以反复使用这些相同的实例。