2011-09-07 54 views
9

讓我們假設我想要一個爲記錄描述行爲的類,其中每個記錄都有一組屬性。如何存儲Java類型,只允許某些特定的類型?

每個屬性都有一個唯一的名稱,應該有對應於一定的Java類型,如整數,字符串短,雙,特定類型的...

可能的類型列表應如限制例如,我只支持Integer和String。

private HashMap<String, Class> attributeList = new HashMap<String, Class>(); 

在上面的例子中的HashMap是屬性的列表,其中作爲密鑰是屬性名字和值應爲屬性(整型或字符串)的類型。

什麼是限制Hashmap值定義的最佳方法?

回答

10

您當然可以使用包裝器方法向地圖添加元素,並在那裏檢查Integer和Sring。但是,那麼你只會遇到運行時錯誤。我同意你的觀點,限制類型獲得靜態錯誤要好得多。

對於這一點,我真的不使用Integer.class和String.class,但是一個枚舉:

enum Types { String, Integer }; 

private Map<String, Types> attributeList = new HashMap<String, Types>(); 

UPDATE:

試想想起來了,還有另外一個(但更復雜)的解決方案,如果你堅持Class對象:您可以使用假枚舉模式,即使用一組常量(通常使用整數2 ^我)像一個枚舉。所以你可以定義你的Class對象作爲常量。這當然不能保證沒有其他類對象被放入地圖中。這就是爲什麼Joshua Bloch第30項說「使用枚舉而不是int常量」。然後你可以使用Checker Framework在使用假枚舉檢查您的常量拉一個額外的類型系統:

private HashMap<String, @Fenum("Types") Class> attributeList 
    = new HashMap<String, @Fenum("Types") Class>(); 

@SuppressWarnings("fenum:assignment.type.incompatible") 
public class TypeEnum { 
    public static final @Fenum("Types") Class INT_CONST = Integer.class; 
    public static final @Fenum("Types") Class STR_CONST = String.class; 
} 

然後你就可以與該類型類別的管制定義地圖

當然,您需要將Fenum Checker包含到您的編譯器中。

+0

我剛剛發佈幾乎相同的答案。該方法足夠清晰和靈活。但是你打算如何處理空值? –

+0

null值呢? – DaveFar

+0

我其實正在尋找那樣的東西! Thx - 會考慮到這一點! –

6

如何使用子類HashMap並重寫put方法,在使用不支持的類型時拋出異常? (未測試......就在我的頭頂。)

class MyAttributes extends HashMap<String, Class> { 
    private Set<Class> allowedTypes; 

    public MyAttributes() { 
     allowedTypes = new HashSet<Class>(); 
     allowedTypes.add(Integer.class); 
    } 
    public Class put(String key, Class value) { 
     if(!allowedTypes.contains(value)) { 
      throw new UnsupportedTypeException(); // <-- Your new exception type. 
     } 
     return super.put(key, value); 
    } 
} 
2

在我看來,你有三種選擇:

  1. 使用定義你擁有了它,當你拉值檢查它是正確的類型之一。
  2. 子類化HashMap並在添加元素時在所述子類中強制實現類型限制。
  3. 有多個地圖,每種類型您想要允許,適當地鍵入。

每個選項都有優點和缺點,您應該使用哪一個選項應該如何使用它。

0

方法過載怎麼樣?

import java.time.LocalDate; 
import java.time.LocalDateTime; 
import java.time.OffsetDateTime; 

public class CarrierDate<T> { 

    private T localDate; 

    private CarrierDate(T localDate) { 
     this.localDate = localDate; 
    } 

    public T getLocalDate() { 
     return localDate; 
    } 

    public static CarrierDate<LocalDate> instance(LocalDate date) { 
     return new CarrierDate<>(date); 
    } 

    public static CarrierDate<LocalDateTime> instance(LocalDateTime date) { 
     return new CarrierDate<>(date); 
    } 

    public static CarrierDate<OffsetDateTime> instance(OffsetDateTime date) { 
     return new CarrierDate<>(date); 
    } 
} 
相關問題