2013-10-21 25 views
1

假設我想要一個int []數組被所有枚舉實例共享。下面是一個例子爲枚舉提供公共數據的更好方法

public enum SampleEnum { 
    Enum1(1), Enum2(2), Enum3(3), Enum4(4); 

    private int[] values; 

    private static final int[] SharedValues = {1, 2, 3, 4, 5}; 
    private static final int ValueCount = SharedValues.length; 

    private SampleEnum(int factor) { 
     // I prefer to calculate data once within constructor 
     values = new int[ValueCount]; 
     for (int i=0; i<ValueCount; i++) 
      values[i] = SharedValues[i] * factor; 
    } 

    private int[] getValues() { 
     return values; 
    }  
} 

你猜怎麼着:我得到消息都ValueCount和 SharedValues「不能在初始化中引用靜態枚舉場」。

該問題可以通過將靜態陣列中的單獨的類被克服:

class SampleEnumData { 
    static final int[] SharedValues = {1, 2, 3, 4, 5}; 
} 


public enum SampleEnum { 
    Enum1(1), Enum2(2), Enum3(3), Enum4(4); 

    private int[] values; 

    private SampleEnum(int factor) { 
     // I prefer to calculate data once within constructor 
     int[] sharedValues = SampleEnumData.SharedValues; 
     int valueCount = sharedValues.length; 
     values = new int[valueCount]; 
     for (int i=0; i<valueCount; i++) 
      values[i] = sharedValues[i] * factor; 
    } 

    private int[] getValues() { 
     return values; 
    }  
} 

但這看起來更作爲彆扭貼片,不是邏輯溶液。

有沒有在枚舉初始值設定項中引用靜態類的原因?

+0

構造在靜態字段全部被初始化之前調用,請參閱http://stackoverflow.com/questions/443980/why-cant-enums-constructor-access-static-fields/444000#444000 – BlackJoker

+0

謝謝J.Rush。據我所知,所有類都是這種情況,不僅僅是枚舉。元素的第一個實例化會觸發靜態構造函數並初始化所有靜態字段。爲什麼枚舉有一個特殊的限制? – cyanide

回答

3

有沒有在枚舉初始值設定項中引用靜態類的原因?

這是一個靜態你沒有允許訪問,並有一個很好的理由:該領域仍然有其初始值,因爲枚舉成員將之前被初始化以後的任何靜態字段初始化器。如果你試圖填充由枚舉的某個方面鍵入的地圖,這通常是一個問題 - 你真的想在構造函數中執行總體,但是你不能,因爲地圖不會被創建。

選項:

  • 其中已建成所有實例後執行的靜態初始化塊完成所有values初始化。這裏的缺點是,如果你希望這個字段是最終的,你需要首先創建這個數組,這意味着知道這個數組有多大才能訪問數據。 (由於values()方法在這裏也有提供,所以你的名字的選擇是不幸的,請注意。)
  • 使用私有嵌套類作爲靜態字段初始化的「持有者」。這就像你的第二個解決方案,但不暴露課堂。

後一種方法可能是最簡單的,說實話。

public enum SampleEnum { 
    ... 

    private static class SampleEnumData { 
     static final int[] SHARED_VALUES = {1, 2, 3, 4, 5}; 
    } 
} 
+0

謝謝你的廣泛評論 – cyanide

0

只是想提供另一個例子。我試圖創建一個字段的偏移量/長度字典,它保證了唯一的名稱,並且對某些移動字段,在中間添加新字段等方面具有一定的彈性。

嘗試引用偏移這樣,當我遇到這種「不能訪問靜態字段」傳來:

enum Fields1 { 
     FIELD1(4), FIELD2(1), FIELD3(8), FIELD4(8);   

     private static int nextOfs = 0; 

     public final int size; 
     public final int offset; 

     private Fields1(int size) { 
      this.size = size; 
      this.offset = nextOfs; // Cannot refer to the static enum field Fields1.nextOfs within an initializer 
      nextOfs += size;  // Same here 
     } 
    } 

閱讀這篇文章,它的答案後,我跳槽到這一點:

enum Fields { 
    FIELD1(4), FIELD2(1), FIELD3(8), FIELD4(8); 

    public final int size; 
    public final int offset; 

    private Fields(int size) { 
     this.size = size; 
     this.offset = OffsetAllocator.FieldsAllocator.getNextOfs(size); 
    } 

    private static final class OffsetAllocator { 
     private static final OffsetAllocator FieldsAllocator = new OffsetAllocator(); 

     private int nextOfs = 0; 

     private final int getNextOfs(int size) { 
      int ofs = nextOfs; 
      nextOfs += size; 
      return ofs; 
     } 
    } 
} 
+0

對我來說,看起來並不是一個有效的解決方案,因爲每次偏移將被重新計算(就像以前沒有發生過任何事情!)。更合乎邏輯的方式(由我的帖子建議)會將nextOfs作爲不同類中的靜態字段(比如OffsetClass),因此您可以保留原始代碼,只用OffsetClass.nextOfs替換nextOfs。 – cyanide

+0

我已經在重新計算的開始就失去了你...偏移/大小的成員是最終的並初始化一次。多次訪問FIELD1.offset不會重新計算任何東西......或者你在談論別的東西嗎? – Alexandros