Formatter<T>
知道如何将T
格式化为字符串:
public interface Formatter<T> {
String format(final T t);
}
我希望有Map
个格式化程序,一个用于Integer
,一个用于Date
等:
Map<Class, Formatter> formatters;
预期用途是:
formatters.put(Integer.class, new Formatter<Integer>() {
public String format(Integer i) {
return i.toString;
}
});
是否有某种方法可以强制键值在Class
类型上达成一致?如果我说put(Integer.class, new Formatter<Integer>(){...})
它会起作用,但put(Integer.class, new Formatter<Date>(){...})
不会吗?
我现在正在尝试使用的是什么?作为类型:
Map<Class<?>, Formatter<?>> formatters;
但是我不能在这张地图中使用格式化程序:
Object obj = Integer.valueOf(15);
formatters.get(obj.getClass()).format(obj);
Error: The method format(capture#3-of ?) in the type Formatter<capture#3-of ?> is not applicable for the arguments (Object)
欢迎任何澄清。
答案 0 :(得分:1)
由于泛型擦除,在语言层面无法做到这一点。您无法在运行时访问泛型类型。 (我不确定我是否正确使用了所有条款)
问题是,如果你传递Integer.class
,那么需要在运行时评估应该有Formatter<Integer>
。 Java中的泛型仅用于在编译期间强制执行类型检查,并在运行时“擦除”。
有一些方法可以在运行时访问泛型类型,但这有点像使用反射的黑客攻击。
它不会像你想象的那样奏效。
答案 1 :(得分:1)
不幸的是,您无法在没有某些先前声明的<T>
泛型类型的情况下在键和值之间创建此类关系。此类型也不应该为类修复,因此它应该能够在每个put
调用中进行更改。
如果这是一个选项,请考虑使用泛型类型的方法,如
@SuppressWarnings("unchecked")
public static <T> void putSafe(Class<T> key, Formatter<T> value) {
formatters.put(key, (Formatter<Object>) value);
}
会将一些值放入地图中,例如可能是您班级中的私人字段
private static Map<Class<?>, Formatter<Object>> formatters
= new HashMap<Class<?>, Formatter<Object>>();
此外,您无法使用format
引用中的Formatter<?>
方法。这种引用可以指向Formatter<Integer>
或Formatter<Date>
或任何其他类型的Formatter,编译器将无法确定您使用的是哪种,因此您可能会使用Formatter<Date>
在Integer
对象上(同样的问题,为什么Java不允许您在add
引用中使用List<?>
方法 - 因为我们不知道哪种类型的列表引用允许执行{ {1}}如果列入实际的苹果列表add(new Banana)
)
要解决此问题,您可以明确说明地图将存储List<Apple>
,并且由于Formatter<Object>
只要扩展对象就能接受任何类型的数据。这种方法的唯一问题是format
无法引用Formatter<Object>
[1],因此您必须明确地将传递的格式化程序转换为Formatter<Integer>
,这通常可能不安全[2]并且你会被编译器警告它,但在这种情况下你不应该没事,所以你可以抑制这个警告。
[1]与Formatter<Object>
类似,无法引用List<Fruit>
,因为通过水果列表,您可以将List<Apple>
添加到Banana
<列表中登记/>
[2]将Apples
转换为List<Apple>
通常不是最好的主意,编译器会警告我们这种方法
答案 2 :(得分:1)
我的解决方案需要一个抑制警告,但它会确保,泛型类型是相同的:
public class Example {
private static Map<Class<?>, Formatter<?>> FORMATTERS =
synchronizedMap(new HashMap<Class<?>, Formatter<?>>());
public static <T> void addFormatter(Class<T> clazz, Formatter<T> formatter) {
FORMATTERS.put(clazz, formatter);
}
}
interface Formatter<T> {
String format(final T value);
}
更新:我添加了Pshemo的解决方案,它首先给了我一个编译错误,但现在有效。好奇,但是。上面显示的代码现在是两个解决方案的合并,它删除了丑陋的@SuppressWarnings("unchecked")
。