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 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |