關於Android中使用Enum的一點總結

月光邊境發表於2018-01-18

列舉是Java 1.5版本增加的特性,列舉是指由一組固定的常量組成的合法值的型別,在還沒有引入列舉的時候,為了表示列舉型別我們常用的方法是宣告一組靜態int 常量。在Effective Java中作者分析了這種模式的許多脆弱之處,因此推薦使用列舉來代替靜態常量方案。

####Effective Java中列舉了使用列舉的的優點:

  1. 列舉提供了編譯時的型別安全;
  2. 包含同名常量的多個列舉型別可以在一個系統中和平共處;
  3. 允許新增任意的方法和域,並實現任意的介面,列舉提供了所有Object方法的高階實現,並實現了Comparable和Serializable介面。

####但是最近在瀏覽Google的官方文件的時候發現,Google是並不不推薦在Android中使用列舉的。 Google的的依據是:

  1. 列舉通常會比靜態常量多使用超過一倍的記憶體;
  2. 在每一個類(包括匿名內部類)中多生成500byte的.class的檔案;
  3. 每一個類的例項有12-16個位元組的RAM開銷;

總結一下: 列舉相對靜態常量最大的有點在於編譯時型別安全,但是記憶體開銷比使用靜態常量大。

####Google為了彌補靜態常量的缺陷,提出了使用IntDef 和StringDef兩個註解來提供編譯時的型別安全 首先引入依賴:

compile 'com.android.support:support-annotations:24.1.1'
複製程式碼

以@IntDef為例的使用方法:

 public class MainActivity extends AppCompatActivity {
        //宣告靜態常量
        public static final int MERCURY = 0;
        public static final int VENUS = 1;
        public static final int EARTH = 2;
        public static final int MARS = 3;
        public static final int JUPITER = 4;
        public static final int SATURN = 5;
        public static final int URANUS = 6;
        public static final int NEPTUNE = 7;

        //用一個@IntDef({})將其全部變數包含,其次需要一個Retention宣告其保留級別,最後定義其介面名稱
        @IntDef({MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE})
        @Retention(RetentionPolicy.SOURCE)
        public @interface Planet {
        }

        @Planet
        int currentPlanet;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            @Planet int planet = getCurrentPlanet();
            switch (planet) {
                case MERCURY:
                    break;
                case VENUS:
                    break;
                case EARTH:
                    break;
                case MARS:
                    break;
                case JUPITER:
                    break;
                case SATURN:
                    break;
                case URANUS:
                    break;
                case NEPTUNE:
                    break;
                default:
                    break;
            }
            //傳個8  有錯誤提示
            //setCurrentPlanet(8);
        }

        //只要一個變數使用了@Planet註解,那麼他的值必須屬於Planet
        public void setCurrentPlanet(@Planet int currentPlanet) {
            this.currentPlanet = currentPlanet;
        }

        @Planet
        private int getCurrentPlanet() {
            //如果返回值不屬於Planet,那麼編譯器會提示錯誤 保證了編譯時安全
            return currentPlanet;
        }
    }
複製程式碼

相關文章