Last year I wrote “Shouldn’t EnUms be used in Android?” If you haven’t seen the article, I’ll give you a brief introduction. In this article, I explain the historical reasons why we should not use Enum in Android, whether we should use Enum at all at this point, and the alternatives in Kotlin.

Today we’ll continue talking about enums and why there is hidden overhead When enums are used with When, and how to avoid it.


So what does ordinal in Enum mean?

So where is the cost?

In other words, whenever we use Enum and WHEN somewhere, the compiler will generate a new class XXX$WhenMappings to assist with the when logic.

If you have read the book “Understanding the Java Virtual Machine”, it is described in chapter 7 of the Virtual machine class loading mechanism:

In the Java language, type loading, linking, and initialization are done at runtime.

At the same time also

If the class has not been initialized, it needs to be initialized first.

At this point we finally find out where the hidden overhead for Enum and When is:

If you have Enum and When in many places, the compiler will generate countless XXX’s for usThe EnumSwitchMapping$0 array, when executed at runtime, adds time overhead for loading and instantiating each class, as well as increasing the size of the resulting binary file due to the addition of new classes.

So why does this happen?

Let’s look at XXX firstEnumSwitchMappingWhen you initialize a WhenMappings method, it will not be pasted), and then make the comparison.

So it can be seen that XXXWhenMappings for comparison.

While researching, I came across a quote from a jakewharton article

The switch map indirection created by javac is useful when the enum may be recompiled separately from the callers.

That is, the temporary variable javac creates is useful when Enum and its caller can be compiled separately. That is, when we compile the Enum and MainActivity files in Javac, the compiler stores the value of the Enum in a temporary variable and stores it in the MainActivity call stack. If you modify the Enum class individually, When only Enum is compiled, MainActivity’s stack still holds the value of the previous Enum.

This seems to me to be a safety concern.

I’m going to share with you another quote from jakewharton:

Android applications are packaged as a single unit, so the indirection is nothing but wasted binary size and runtime overhead.

This means that Android is compiled as a whole and there is no problem with separate compilations, so the compiler introduces a temporary variable that is completely redundant and only causes large binaries and runtime overhead.

Now that we know what causes this overhead, it turns out to be the compiler’s pot, so how can we avoid this overhead?

To turn obfuscation on, use minifyEnabled true

When obfuscating is enabled, the R8 compiler removes this unnecessary temporary variable. Here is the bytecode stack after obfuscating.

Note, however, that if you’re using Android Studio 3.6 or below, kotlin may still have this hidden overhead, even if obfuscations are turned on. Because Java names the temporary variable differently from Kotlin’s, versions R8 prior to 3.6 were not optimized for this, so only later versions will eliminate this hidden overhead.

That’s all for today’s post. Keep an eye out for Android | Kotlin!