Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/234.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 我应该严格避免在Android上使用枚举吗?_Java_Android_Enums - Fatal编程技术网

Java 我应该严格避免在Android上使用枚举吗?

Java 我应该严格避免在Android上使用枚举吗?,java,android,enums,Java,Android,Enums,我曾在如下界面中定义一组相关常量,如捆绑键: public interface From{ String LOGIN_SCREEN = "LoginSCreen"; String NOTIFICATION = "Notification"; String WIDGET = "widget"; } 这为我提供了一种更好的方法,将相关常量分组在一起,并通过静态导入(而不是实现)使用它们。我知道Android框架也以同样的方式使用常量,比如Toast.LENTH_LONG,V

我曾在如下界面中定义一组相关常量,如
捆绑
键:

public interface From{
    String LOGIN_SCREEN = "LoginSCreen";
    String NOTIFICATION = "Notification";
    String WIDGET = "widget";
}
这为我提供了一种更好的方法,将相关常量分组在一起,并通过静态导入(而不是实现)使用它们。我知道Android框架也以同样的方式使用常量,比如Toast.LENTH_LONG
View.GONE

然而,我经常觉得
javaenum
提供了更好、更强大的方法来表示常量

但是在
Android
上使用
enums
是否存在性能问题

经过一番研究,我最终陷入了困惑。从这个问题 很明显,
Google
已经将“避免枚举”从其性能提示中删除,但在其官方培训文档部分,它明确指出:“枚举通常需要两倍于静态常量的内存。你应该严格避免在Android上使用枚举。”这仍然有效吗?(在
Java
1.6之后的版本中)

我观察到的另一个问题是,使用
Bundle
意图发送
enum
,我应该通过序列化发送它们(即
putSerializable()
,我认为与基元
putString()
方法相比,这是一个昂贵的操作,尽管
enum
是免费提供的)

有人能澄清一下,在
Android
中,哪一种方式是最好的表达方式吗?我是否应该严格避免在
Android
上使用
enums

我应该严格避免在Android上使用枚举吗

不,“严格”的意思是它们太差了,根本不应该被使用。在极端情况下可能会出现性能问题,例如使用枚举(ui线程上的连续)执行的许多(数千或数百万)操作。更常见的是网络I/O操作,这些操作应该严格在后台线程中进行。 枚举最常见的用法可能是某种类型的检查——无论对象是this还是this,它的速度如此之快,您都不会注意到单个枚举比较和整数比较之间的差异

有人能澄清一下,在Android中,哪一种方式是最好的表达方式吗


这方面没有一般的经验法则。使用任何适合你并帮助你准备好应用程序的工具。稍后优化-当您注意到有一个瓶颈会减慢应用程序的某些方面时。

当您需要它的功能时,请使用
enum
不要严格避免它

JavaEnum功能更强大,但如果您不需要它的特性,可以使用常量,它们占用的空间更少,而且它们本身也可以是原语

何时使用枚举:
  • 类型检查-您只能接受列出的值,并且它们不是连续的(请参见下面我在这里称之为连续的内容)
  • 方法重载-每个枚举常量都有自己的方法实现

    public enum UnitConverter{
        METERS{
            @Override
            public double toMiles(final double meters){
                return meters * 0.00062137D;
            }
    
            @Override
            public double toMeters(final double meters){
                return meters;
            }
        },
        MILES{
            @Override
            public double toMiles(final double miles){
                return miles;
            }
    
            @Override
            public double toMeters(final double miles){
                return miles / 0.00062137D;
            }
        };
    
        public abstract double toMiles(double unit);
        public abstract double toMeters(double unit);
    }
    
  • 更多数据-一个常量包含多个不能放入一个变量中的信息

  • 复杂数据-您经常需要对数据进行操作的方法
不使用枚举时:
  • 您可以接受一种类型的所有值,并且常量只包含这些最常用的值
  • 您可以接受连续数据

    public class Month{
        public static final int JANUARY = 1;
        public static final int FEBRUARY = 2;
        public static final int MARCH = 3;
        ...
    
        public static String getName(final int month){
            if(month <= 0 || month > 12){
                throw new IllegalArgumentException("Invalid month number: " + month);
            }
    
            ...
        }
    }
    
    公共课月{
    公共静态最终int一月=1;
    公共静态最终int二月=2;
    公共静态最终int三月=3;
    ...
    公共静态字符串getName(最后一个整数月){
    如果(第12个月){
    抛出新的IllegalArgumentException(“无效月号:“+月”);
    }
    ...
    }
    }
    
  • 名称(如您的示例中所示)
  • 对于真正不需要枚举的所有其他内容
枚举占用更多空间
  • 对枚举常量的单个引用占用4个字节
  • 每个枚举常量占用的空间是其字段大小之和,与对象的8字节+开销对齐
  • 枚举类本身占用一些空间
常数占用更少的空间
  • 常量没有引用,因此它是纯数据(即使它是引用,枚举实例也将是对另一引用的引用)
  • 可以将常量添加到现有类中-无需添加其他类
  • 常数可以内联;它带来了扩展的编译时特性(如空检查、查找死代码等)

如果枚举只有值,则应尝试使用IntDef/StringDef,如下所示:

示例:而不是:

enum NavigationMode {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS} 
您使用:

@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
@Retention(RetentionPolicy.SOURCE)
public @interface NavigationMode {}

public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
在将其作为参数/返回值的函数中,使用:

@NavigationMode
public abstract int getNavigationMode();

public abstract void setNavigationMode(@NavigationMode int mode);
如果枚举很复杂,请使用枚举。没那么糟

要比较枚举与常量值,请阅读以下内容:


他们的示例是一个具有2个值的枚举。与使用常量整数时的128字节相比,dex文件需要1112字节。这很有意义,因为枚举是真实的类,而不是它在C/C++上的工作方式。

我想补充一点,当您声明一个列表或映射时,其中键或值是其中一个注释接口时,不能使用@Annotations。 出现错误“此处不允许批注”

enum值{1,2,3}
Map myMap;//这很有效
// ... 但是
公共静态最终整数=1;
公共静态最终int 2=2;
公共静态最终int 3=3;
@保留(RetentionPolicy.SOURCE)
@IntDef({1,2,3})
公共@接口值{}
映射myMap;//***错误***

因此,当您需要将其打包到列表/映射中时,请使用enum,因为它们可以添加,但@annotated int/string组无法添加。

除了前面的答案之外,我还想补充一点,如果您使用的是Proguard(您肯定应该这样做以减小大小并混淆代码),那么您的
enum将
enum Values { One, Two, Three }
Map<String, Values> myMap;    // This works

// ... but ...
public static final int ONE = 1;
public static final int TWO = 2;
public static final int THREE = 3;

@Retention(RetentionPolicy.SOURCE)
@IntDef({ONE, TWO, THREE})
public @interface Values {}

Map<String, @Values Integer> myMap;    // *** ERROR ***