我正在观看两位 Android 工程师谈论 Android 中的垃圾收集的视频。在介绍中,他们对枚举进行了一些玩笑。 Romain Guy 说:“我必须纠正你。枚举,它们不分配。这就是重点。”起初,我认为罗曼只是开了个玩笑,因为枚举在其他语言中是这样工作的。但在此之后,Chet 似乎承认枚举确实不分配,而是做一些“内存相关”的事情(意味着:生活在堆栈上)。这种 react 让我感到困惑。
https://youtu.be/Zc4JP8kNGmQ?t=96
根据我的理解,Java 中的枚举基本上是类实例的固定集合和 seeing as Enum
implements Object
从内存角度来看与对象实例化一样好,因此将分配到堆中。
但我可以想象枚举具有一些特殊的地位,因为编译器可以绘制它们的强大属性。类似地,我知道 String
有各种优化,例如文字共享池。
我目前的情况是,我有固定的对象列表,在我的应用程序中用作常量。所以我可以将其实现为枚举或类实例化数组。假设可读性不是问题,那么前者的性能会更高吗?
最佳答案
枚举是对象。像所有对象一样,它们存在于堆中。
确实,如果你反编译一个简单的枚举,例如:
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
您还可以从枚举中获得一些其他特殊的东西(例如保证它们不能反射地创建);但实际上,它们只是普通的对象。
我认为他们试图表达的一点是,枚举不会被分配多次(如果您确实需要单例,它们是实现单例的好方法)。因此,您需要支付少量的固定成本来加载枚举类;但您可以一遍又一遍地重复使用这些相同的实例。
关于java - Java 枚举是否在 Android 运行时分配堆内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53344941/