我收藏的Android开发文章

Android中避免使用枚举类(Enum)

2019-11-04  本文已影响0人  Geekholt

目录

前言

Android官方training文档中有一句话

Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android

http://www.androiddocs.com/training/articles/memory.html

枚举类的好处

在java中,使用枚举类可以保证类型安全提高代码可读性。无论需求如何变化,比如枚举常量增加一个数据,或是增加一条状态,都可以很方便的实现,比直接在全局常量类里定义状态来的便捷

static与Enum比较

public class Test {
    public static final int RED = 1;
    public static final int BLACK = 2;
    public static final int GREEN = 3;
    public static final int YELLOW = 4;

    public int fun(int color) {
        switch (color) {
            case RED:
                return -1;
            case BLACK:
                return -2;
            case GREEN:
                return -3;
            case YELLOW:
                return -4;
            default:
                return 0;
        }
    }
}

初步结论:使用Enum会比static增加2-3倍的byte,从而增加apk的体积

Enum源码分析

我们创建了一个枚举类Color

public enum Color {
    RED, GREEN, BLACK, YELLOW
}

编译项目,在app/build/intermediates/javac/debug/classes/项目名称目录下,可以找到Color.class文件,执行javap -c Color.class命令对class文件进行反编译,结果如下所示

Compiled from "Color.java"
public final class com.geekholt.kotlinandjavademo.Color extends java.lang.Enum<com.geekholt.kotlinandjavademo.Color> {
  public static final com.geekholt.kotlinandjavademo.Color RED;

  public static final com.geekholt.kotlinandjavademo.Color GREEN;

  public static final com.geekholt.kotlinandjavademo.Color BLACK;

  public static final com.geekholt.kotlinandjavademo.Color YELLOW;

  public static com.geekholt.kotlinandjavademo.Color[] values();
    Code:
       0: getstatic     #1                  // Field $VALUES:[Lcom/geekholt/kotlinandjavademo/Color;
       3: invokevirtual #2                  // Method "[Lcom/geekholt/kotlinandjavademo/Color;".clone:()Ljava/lang/Object;
       6: checkcast     #3                  // class "[Lcom/geekholt/kotlinandjavademo/Color;"
       9: areturn

  public static com.geekholt.kotlinandjavademo.Color valueOf(java.lang.String);
    Code:
       0: ldc           #4                  // class com/geekholt/kotlinandjavademo/Color
       2: aload_0
       3: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
       6: checkcast     #4                  // class com/geekholt/kotlinandjavademo/Color
       9: areturn

  static {};
    Code:
       0: new           #4                  // class com/geekholt/kotlinandjavademo/Color
       3: dup
       4: ldc           #7                  // String RED
       6: iconst_0
       7: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      10: putstatic     #9                  // Field RED:Lcom/geekholt/kotlinandjavademo/Color;
      13: new           #4                  // class com/geekholt/kotlinandjavademo/Color
      16: dup
      17: ldc           #10                 // String GREEN
      19: iconst_1
      20: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      23: putstatic     #11                 // Field GREEN:Lcom/geekholt/kotlinandjavademo/Color;
      26: new           #4                  // class com/geekholt/kotlinandjavademo/Color
      29: dup
      30: ldc           #12                 // String BLACK
      32: iconst_2
      33: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      36: putstatic     #13                 // Field BLACK:Lcom/geekholt/kotlinandjavademo/Color;
      39: new           #4                  // class com/geekholt/kotlinandjavademo/Color
      42: dup
      43: ldc           #14                 // String YELLOW
      45: iconst_3
      46: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      49: putstatic     #15                 // Field YELLOW:Lcom/geekholt/kotlinandjavademo/Color;
      52: iconst_4
      53: anewarray     #4                  // class com/geekholt/kotlinandjavademo/Color
      56: dup
      57: iconst_0
      58: getstatic     #9                  // Field RED:Lcom/geekholt/kotlinandjavademo/Color;
      61: aastore
      62: dup
      63: iconst_1
      64: getstatic     #11                 // Field GREEN:Lcom/geekholt/kotlinandjavademo/Color;
      67: aastore
      68: dup
      69: iconst_2
      70: getstatic     #13                 // Field BLACK:Lcom/geekholt/kotlinandjavademo/Color;
      73: aastore
      74: dup
      75: iconst_3
      76: getstatic     #15                 // Field YELLOW:Lcom/geekholt/kotlinandjavademo/Color;
      79: aastore
      80: putstatic     #1                  // Field $VALUES:[Lcom/geekholt/kotlinandjavademo/Color;
      83: return
}

把上面的字节码文件翻译成java大致如下所示

public final class Color extends java.lang.Enum<Color> {
    public static final Color RED;

    public static final Color GREEN;

    public static final Color BLACK;

    public static final Color YELLOW;

    static {
        RED = new Color("RED", 0);

        GREEN = new Color("GREEN", 1);

        BLACK = new Color("BLACK", 2);

        YELLOW = new Color("YELLOW", 3);

        VALUES = new Color[]{RED, GREEN, BLACK, YELLOW};
    }

    public static Color[] values() {
        Color tmp = new Color[VALUES.length];
        system.arraycopy(VALUES, 0, tmp, 0, VALUES.length);
        return tmp;
    }

    public static Color valueOf(String name) {
        return Enum.valueOf(name);
    }
}

由此我们可以得出以下结论:

解决方案

  1. 为了弥补 Android 平台不建议使用枚举的缺陷,官方推出了两个注解,@IntDef@StringDef,用来提供编译期的类型检查
  1. 如果开启了Proguard可以在很多情况下将枚举Enum优化到整数对象。

结论

在android中使用枚举类不仅会增加apk体积,同时也会增加运行时内存,所以在架构设计上还是要慎用枚举类。如果希望进行编译期类型检查可以使用@IntDef@StringDef类保证类型安全

上一篇下一篇

猜你喜欢

热点阅读