java – HashMap中的消费者映射类
|
我想创建一个IdentityHashMap< Class< T>,Consumer< T>>.基本上,我想用一种方法来映射一个类型,说明如何处理这种类型. 我想动态地能够用对象X说,执行Y.我能做到 private IdentityHashMap<Class<?>,Consumer<?>> interceptor = new IdentityHashMap<>(); 但它很糟糕,因为我在使用它时必须在lamba中投射对象. 例: interceptor.put(Train.class,train -> {
System.out.println(((Train)train).getSpeed());
});
我想做的是 private <T> IdentityHashMap<Class<T>,Consumer<T>> interceptor = new IdentityHashMap<>(); 但似乎不允许这样做.有没有办法做到这一点 ?使用此类型的方法映射类型的最佳解决方法是什么? 解决方法这基本上就像 type-safe heterogeneous container described by Joshua Bloch一样,除了你不能使用Class来强制转换结果.奇怪的是,我找不到SO上存在的一个很好的例子,所以这里有一个: package mcve;
import java.util.*;
import java.util.function.*;
class ClassToConsumerMap {
private final Map<Class<?>,Consumer<?>> map =
new HashMap<>();
@SuppressWarnings("unchecked")
public <T> Consumer<? super T> put(Class<T> key,Consumer<? super T> c) {
return (Consumer<? super T>) map.put(key,c);
}
@SuppressWarnings("unchecked")
public <T> Consumer<? super T> get(Class<T> key) {
return (Consumer<? super T>) map.get(key);
}
}
这是类型安全的,因为键和值之间的关系是由put方法的签名强制执行的. 关于Java泛型的局限性的一个令人讨厌的事情是,这些容器中的一个不能为通用值类型编写,因为没有办法做到例如: class ClassToGenericValueMap<V> {
...
public <T> V<T> put(Class<T> key,V<T> val) {...}
public <T> V<T> get(Class<T> key) {...}
}
其他说明: >我会使用常规的HashMap或LinkedHashMap. HashMap得到了更好的维护,并且具有许多IdentityHashMap所没有的优化. 有时人们希望通过类到消费者的地图做这样的事情: public <T> void accept(T obj) {
Consumer<? super T> c = get(obj.getClass());
if (c != null)
c.accept(obj);
}
也就是说,给定任何对象,找到绑定到该对象类的映射中的使用者,并将该对象传递给使用者的accept方法. 但是,该示例不会编译,因为getClass()实际上被指定为返回Class<? extends | T |>,其中| T |表示T的擦除(参见JLS §4.3.2.)在上面的例子中,T的擦除是Object,所以obj.getClass()返回一个普通的Class<?>. 这个问题可以通过capturing helper method解决: public void accept(Object obj) {
accept(obj.getClass(),obj);
}
private <T> void accept(Class<T> key,Object obj) {
Consumer<? super T> c = get(key);
if (c != null)
c.accept(key.cast(obj));
}
此外,如果您想要一个返回任何适用消费者的get的修改版本,您可以使用以下内容: public <T> Consumer<? super T> findApplicable(Class<T> key) {
Consumer<? super T> c = get(key);
if (c == null) {
for (Map.Entry<Class<?>,Consumer<?>> e : map.entrySet()) {
if (e.getKey().isAssignableFrom(key)) {
@SuppressWarnings("unchecked")
Consumer<? super T> value =
(Consumer<? super T>) e.getValue();
c = value;
break;
}
}
}
return c;
}
这让我们可以将普通超类型消费者放在地图中,如下所示: ctcm.put(Object.class,System.out::println); 然后使用子类类检索: Consumer<? super String> c = ctcm.findApplicable(String.class);
c.accept("hello world");
这是一个稍微更一般的例子,这次使用的是UnaryOperator并且没有有界通配符: package mcve;
import java.util.*;
import java.util.function.*;
public class ClassToUnaryOpMap {
private final Map<Class<?>,UnaryOperator<?>> map =
new HashMap<>();
@SuppressWarnings("unchecked")
public <T> UnaryOperator<T> put(Class<T> key,UnaryOperator<T> op) {
return (UnaryOperator<T>) map.put(key,op);
}
@SuppressWarnings("unchecked")
public <T> UnaryOperator<T> get(Class<T> key) {
return (UnaryOperator<T>) map.get(key);
}
}
The (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
