2011-09-07 27 views
9

Supponiamo che voglia avere una classe che agisce come descrittore per i record, in cui ogni record ha una serie di attributi.Come posso archiviare tipi Java, permettendo solo alcuni specifici?

Ogni attributo ha un nome univoco e dovrebbe avere un tipo specifico che corrisponde ad un certo tipo di Java come ad esempio Integer, String, corto, doppio, ...

L'elenco dei possibili tipi deve essere limitato, come Suppongo solo Integer e String, per esempio.

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

Nell'esempio sopra HashMap è un elenco di attributi dove la chiave è il nome di attributo e il valore dovrebbe essere il tipo di attributo (interi o stringhe).

Quale sarebbe il modo migliore per limitare la definizione del valore di Hashmap?

risposta

10

Si potrebbe ovviamente utilizzare i metodi wrapper per aggiungere elementi alla mappa e fare un controllo per intero e Sring. Ma poi ricevi solo errori di runtime. Sono d'accordo con te che limitare il tipo per ottenere errori statici è molto meglio.

Per questo, non avrei effettivamente utilizzare Integer.class e String.class, ma un enum:

enum Types { String, Integer }; 

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

UPDATE:

Vieni a pensarci bene, non v'è un altro (ma più complicato), se hai avere attaccare agli oggetti Class: Puoi usare il modello di enum finto, cioè usare un insieme di costanti (di solito gli interi 2^i sono usati) come un enum. Quindi puoi definire gli oggetti di classe come costanti. Ciò ovviamente non garantisce che nessun altro oggetto di classe venga inserito nella mappa. Ecco perché l'articolo 30 di Joshua Bloch dice "Usa enum invece di costanti int".Ma è quindi possibile utilizzare la Checker Framework per tirare un sistema di tipo aggiuntivo sopra i vostri costanti utilizzando il falso Enum checker:

@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; 
} 

Quindi è possibile definire la mappa con una restrizione del tipo Classe:

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

Ovviamente, è necessario includere lo Fenum Checker nel compilatore.

+0

Stavo per pubblicare quasi la stessa risposta. L'approccio è abbastanza chiaro e flessibile. Ma cosa hai intenzione di fare con valori nulli? –

+0

E i valori nulli? – DaveFar

+0

In realtà stavo cercando esattamente qualcosa del genere! Thx - ci penserà! –

6

E la sottoclasse di HashMap e sovrascrivere il metodo put, generando un'eccezione quando viene utilizzato un tipo non supportato? (Testato ... appena fuori dalla parte superiore della mia testa.)

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

come la vedo io, sono disponibili tre opzioni:

  1. Usare la definizione come si deve, e quando si tira la valore verifica che sia uno dei tipi corretti.
  2. Sottoclassi HashMap e applica i limiti di tipo in detta sottoclasse quando si aggiungono gli elementi.
  3. Avere più mappe, una per ogni tipo che si desidera consentire, digitato in modo appropriato.

Ogni opzione presenta vantaggi e svantaggi, e quale si dovrebbe usare dovrebbe essere determinato da come lo si utilizzerà.

0

E il sovraccarico del metodo?

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); 
    } 
} 
Problemi correlati