让我们假设我想要一个作为记录描述符的类,其中每个记录都有一组属性。
每个属性都有一个唯一的名称,并且应该具有与某个Java类型相对应的特定类型,例如Integer,String,Short,Double,......
应该限制可能的类型列表,例如我只支持Integer和String。
private HashMap<String, Class> attributeList = new HashMap<String, Class>();
在上面的例子中,HashMap是一个属性列表,其中key是属性名称,值应该是属性的类型(Integer或String)。
限制Hashmap值定义的最佳方法是什么?
答案 0 :(得分:10)
您当然可以使用包装器方法向地图添加元素,并检查Integer和Sring。但是你只会遇到运行时错误。我同意你的观点,限制类型以获得静态错误要好得多。
为此,我实际上不会使用Integer.class和String.class,而是使用枚举:
enum Types { String, Integer };
private Map<String, Types> attributeList = new HashMap<String, Types>();
更新:
想想看,还有另一个(但更复杂的)解决方案,如果你有坚持Class对象:你可以使用伪枚举模式,即使用一组常量(通常使用整数2 ^ i)就像枚举一样。因此,您可以将Class对象定义为常量。当然,这并不能保证没有其他类对象被放入地图中。这就是为什么Joshua Bloch第30项说“使用枚举而不是int常量”。 但是然后您可以使用Checker Framework使用假枚举检查器在常量上拉出其他类型系统:
@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;
}
然后,您可以使用Class类型的限制来定义地图:
private HashMap<String, @Fenum("Types") Class> attributeList
= new HashMap<String, @Fenum("Types") Class>();
当然,您需要将Fenum Checker包含在编译器中。
答案 1 :(得分: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 :(得分:2)
在我看来,你有三个选择:
每个选项都有优点和缺点,您应该使用哪一个应该根据您的使用方式来决定。
答案 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);
}
}