欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-12 11:33:19
...

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

二 枚举原理:

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

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

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

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

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

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

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类型的,也就表明只能被实例化一次


相关标签: Enum