当前位置: 首页 > 面试题库 >

消费者 映射类 在HashMap中

祁霖
2023-03-14
问题内容

我想创建一个IdentityHashMap<Class<T>, Consumer<T>>。基本上,我想使用一种说明该类型的方法来映射一个类型。

我希望能够动态地说出对象X,执行Y。我可以

private IdentityHashMap<Class<?>, Consumer<?>> interceptor = new IdentityHashMap<>();

但它很烂,因为然后我必须在使用它时将对象投射到兰巴中。

例:

interceptor.put(Train.class, train -> {
    System.out.println(((Train)train).getSpeed());
});

我想做的是

private <T> IdentityHashMap<Class<T>, Consumer<T>> interceptor = new IdentityHashMap<>();

但这似乎是不允许的。有没有办法做到这一点 ?使用此类型的方法映射类型的最佳解决方法是什么?


问题答案:

本质上,这与Joshua
Bloch所描述
的类型安全的异构容器类似,只是您不能使用Class来强制转换结果。

奇怪的是,我找不到SO上存在的一个很好的例子,所以这是一个例子:

package mcve;
import java.util.*;
import java.util.functhtml" target="_blank">ion.*;

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它只能表示擦除类型。

  • 番石榴ClassToInstanceMap在需要的时候可以食用Map<Class<T>, T>

有时人们想通过类对消费者的映射来做这样的事情:

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。)在上面的示例中,擦除Tis
Object,因此obj.getClass()返回一个plain Class<?>

可以使用捕获助手方法解决此问题:

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);
    }
}

第? super一个示例中的有界通配符特定于消费者,我认为不带通配符的示例可能更易于阅读。



 类似资料:
  • 我正在阅读Kafka常见问题解答,他们如下所示。 •每个分区不会被每个使用者组中的多个使用者线程/进程使用。这允许每个进程以单线程方式使用,以保证分区内的使用者的顺序(如果我们将有序消息分割成一个分区并将它们传递给多个使用者,即使这些消息是按顺序存储的,它们有时也会被无序地处理)。 有没有可能,

  • 是否有一种方法以编程方式访问和打印使用者滞后偏移,或者说使用者读取的最后一条记录的偏移与某个生产者写入该使用者分区的最后一条记录的偏移之间的位置差。 要知道我的最终目标是将这个值发送到prometheus进行监视,我应该在上面添加哪些语句来得到滞后偏移值?

  • 我花了几个小时想弄清楚发生了什么,但没能找到解决办法。 这是我在一台机器上的设置: 1名zookeeper跑步 我正在使用kafka控制台生成器插入消息。如果我检查复制偏移量(

  • 问题内容: 我的问题围绕着我想用JPA映射的以下结构: 我的POJO非常简单(没有复合类型等,只有一些原语)。 如何在链接的问题中实施建议?我该如何仅用部分进行注释(当我仅对字段进行注释时,会发生类转换错误,因为HashMap无法转换为Blob,这是问题的根源- 我不能仅对值部分进行注释地图)? 我不确定是否需要使包装类型实现实现可包装List的Serializable,还是仅使用ArrayLis

  • 我已经编写了一个streams应用程序,用于在由5个代理和10个分区组成的集群上与主题对话。我在这里尝试了多种组合,比如10个应用程序实例(在10台不同的机器上),每个实例有1个流线程,5个实例每个实例有2个线程。但由于某种原因,当我签入kafka manager时,分区和流线程之间的1:1映射没有发生。一些线程正在拾取2个分区,而一些线程没有拾取任何分区。你能帮我做同样的事吗??所有线程都是同一

  • Flink kafka消费者有两种类型的消费者,例如: 这两个消费者层次结构扩展了相同的类。我想知道维护编号类背后的设计决策是什么?我们什么时候应该使用其中一种? 我注意到带有数字后缀的类有更多的特性(例如ratelimiting)。 https://github.com/apache/flink/blob/master/flink-connectors/flink-connector-kafka