2011-09-07 11 views
9

Supongamos que quiero tener una clase que actúa como descriptor de registros, donde cada registro tiene un conjunto de atributos.¿Cómo puedo almacenar tipos de Java, permitiendo solo algunos específicos?

Cada atributo tiene un nombre único y debe tener un tipo específico que corresponde a un determinado tipo de Java tales como entero, cadena, corto, doble, ...

La lista de posibles tipos se debe restringir tales como Solo apoyo Integer y String por ejemplo.

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

En el ejemplo anterior el HashMap es una lista de atributos en tanto que la clave es el nombre del atributo y el valor debe ser el tipo de atributo (entero o de cadena).

¿Cuál sería la mejor manera de restringir la definición del valor del Hashmap?

Respuesta

10

Por supuesto, puede utilizar los métodos de envoltura para agregar elementos al mapa, y hacer una verificación de enteros y Sring allí. Pero solo recibes errores de tiempo de ejecución. Estoy de acuerdo con usted en que restringir el tipo para obtener errores estáticos es mucho mejor.

Por eso, en realidad no usaría Integer.class y String.class, pero una enumeración:

enum Types { String, Integer }; 

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

ACTUALIZACIÓN:

Ahora que lo pienso de ella, hay otra (pero más complicado) solución, si tiene para pegar objetos de Clase: Puede usar el patrón de enum falso, es decir usar un conjunto de constantes (generalmente los enteros 2^i se usan) como una enumeración. Entonces puedes definir tus objetos de Clase como las constantes. Eso, por supuesto, no garantiza que no se coloquen otros objetos de clase en el mapa. Es por eso que el artículo 30 de Joshua Bloch dice "Use enumeraciones en lugar de constantes int".Pero a continuación, puede utilizar el Checker Framework para tirar de un sistema de tipo adicional sobre sus constantes utilizando el falso Enum corrector:

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

A continuación, puede definir su mapa con una restricción del tipo Clase:

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

Por supuesto, necesitaría incluir el Fenum Checker en su compilador.

+0

Estaba a punto de publicar casi la misma respuesta. El enfoque es claro y lo suficientemente flexible. Pero, ¿qué vas a hacer con los valores nulos? –

+0

¿Qué hay de los valores nulos? – DaveFar

+0

¡Estaba buscando exactamente algo así! ¡Thx - pensará en eso! –

6

¿Qué hay de la subclase HashMap y anula el método put, lanzando una excepción cuando se usa un tipo no soportado? (No probado ... justo al lado de la parte superior de la cabeza.)

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

Tal como lo veo, usted tiene tres opciones:

  1. Use la definición tal como lo tienes, y cuando se tire de la Verifique que es uno de los tipos correctos.
  2. Subclase el HashMap e impone los límites de tipo en dicha subclase al agregar los elementos.
  3. Tenga varios mapas, uno para cada tipo que desee permitir, escritos correctamente.

Cada opción tiene ventajas y desventajas, y la que debe usar debe estar determinada por la forma en que la usará.

0

¿Qué tal la sobrecarga de métodos?

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); 
    } 
} 
Cuestiones relacionadas