gpt4 book ai didi

java - Consumer 映射到 HashMap 中的 Class

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:48:30 25 4
gpt4 key购买 nike

我想创建一个 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) {...}
}

其他说明:

  • 我会使用常规 HashMapLinkedHashMap为了这。 HashMap维护得更好并且有许多优化 IdentityHashMap没有。

  • 如果有必要使用通用类型,例如 Consumer<List<String>> , 那么你需要使用像 Guava TypeToken 这样的东西作为关键,因为 Class只能代表一个类型的删除。

  • Guava 有一个 ClassToInstanceMap 当你需要 Map<Class<T>, T> 时.

有时人们想用类到消费者的映射来做这样的事情:

public <T> void accept(T obj) {
Consumer<? super T> c = get(obj.getClass());
if (c != null)
c.accept(obj);
}

也就是说,给定任何对象,在映射中找到绑定(bind)到该对象类的消费者并将该对象传递给消费者的 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;
}

这让我们可以将一般父类(super class)型消费者放入 map 中,如下所示:

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 ? super bounded wildcard in the first example is specific to consumers ,我认为没有通配符的示例可能更易于阅读。

关于java - Consumer<T> 映射到 HashMap 中的 Class<T>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44422685/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com