Java 枚举类型原理分析为什么枚举比用静态变量多消耗两倍的内存

一 起源:枚举是一种特殊的数据类型,一般用来列举有限个、同类型的常量。它能保证参数的安全性,如方法声明传入的参数,必须是指定枚举中的常量。但是Android开发文档指出,使用枚举会比使用静态变量多消耗2倍内存。为什么枚举这么耗内存?

二 枚举原理:

定义枚举类  Week  星期一 到 星期五

public enum Week {
    MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY
}

1、使用Android Studio  ReBuildProject 功能会编译成.class子节 码文件

Java 枚举类型原理分析为什么枚举比用静态变量多消耗两倍的内存_第1张图片

2 在 app/build/intermediates/classes/debug/里找到生成的子节码文件为

Java 枚举类型原理分析为什么枚举比用静态变量多消耗两倍的内存_第2张图片

package com.example.xu.mycustomviewdemo;

public enum Week {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY;

    private Week() {
    }
}

3、用jad反编译.class文件,生成Week.jad,jad的下载地址:http://www.javadecompilers.com/jad

jad的使用方法:jad

打开Week.jad为

package com.example.xu.mycustomviewdemo;
public final class Week extends Enum
{
    public static Week[] values()
    {
        return (Week[])$VALUES.clone();
    }

    public static Week valueOf(String name)
    {
        return (Week)Enum.valueOf(com/example/xu/mycustomviewdemo/Week, name);
    }

    private Week(String s, int i)
    {
        super(s, i);
    }
    public static final Week MONDAY;
    public static final Week TUESDAY;
    public static final Week WEDNESDAY;
    public static final Week THURSDAY;
    public static final Week FRIDAY;
    private static final Week $VALUES[];

    static 
    {
        MONDAY = new Week("MONDAY", 0);
        TUESDAY = new Week("TUESDAY", 1);
        WEDNESDAY = new Week("WEDNESDAY", 2);
        THURSDAY = new Week("THURSDAY", 3);
        FRIDAY = new Week("FRIDAY", 4);
        $VALUES = (new Week[] {
            MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
        });
    }
}

从反编译的代码来看,我们定义的枚举,编译器会将其转换成一个类,这个类继承自java.lang.Enum类,除此之外,编译器还会帮我们生成多个枚举类的实例,赋值给我们定义的枚举类型常量【即static包里】,并且还声明了一个枚举对象的数组,保存了所有的枚举对象。生成的诸多对象,对象数组,远比静态变量占据内存多。

三 替代枚举的方法:

方法一 注解

1 官方提供的注解库

  1. compile 'com.android.support:support-annotations:24.2.0'  

2 定义

@IntDef({NewWeek.MONDAY, NewWeek.TUESDAY})
@Retention(RetentionPolicy.SOURCE)
public @interface NewWeek {
    public static final int MONDAY = 0;
    public static final int TUESDAY = 1;
}

3 使用

private void setEnum(@NewWeek int  week){
     。。
    }

setEnum(NewWeek.MONDAY);

方法二:接口常量

接口变量默认都是public static final的也就是常量形式

public interface WeekInterface {
    int Monday = 0;
    int TUESDAY = 1;
}

jad 反编译子节码为:

interface WeekInterface {
  public static final int Monday;
  public static final int TUESDAY;
}

四 枚举实现单例

首先枚举里可以声明类,实例变量 和方法

enum Type{
    A,B,C,D;

    static int value;
    public static int getValue() {
        return value;
    }

    String type;
    public String getType() {
        return type;
    }
}

枚举定义单例:

/**
 *  需要被实例的类
 */

public class MediaManager {
}

枚举实现MediaManager单例

public enum  MediaManagerCreater {
    // 枚举实例
    CREATERINSTANCE ;

    // 要被生名单例类的对象
    private MediaManager mediaManager;
    // 枚举构造   只生成一次
    MediaManagerCreater(){
        mediaManager = new MediaManager();
    }

    /**
     *  获取对应实例
     */
    public MediaManager getManagerInstance(){
        return mediaManager;
    }
}

获取单例为:

  MediaManagerCreater.CREATERINSTANCE.getManagerInstance();

原理:

1 枚举的构造函数是私有的

我们访问枚举实例时会执行构造方法,同时每个枚举实例都是static final类型的,也就表明只能被实例化一次


你可能感兴趣的:(Android)