java - Consumers<X> 数组中的 ArrayStoreException

标签 java arrays reference observer-pattern consumer

我正在存储对 BiConsumers<Integer, X> 的引用适应Consumer<Integer> :

public void setConsumer(BiConsumer<Integer, X> consumer) {
    fieldConsumer = integer -> consumer.accept(integer, fieldSubject);
}

但我需要其中 2 个,所以我更改了代码以使用数组:

private Consumer<Integer>[] fieldConsumers;

public MyClass(int numberOfConsumers) {
    Consumer<Integer> consumer = integer -> {};
    fieldConsumers= (Consumer<Integer>[]) Array.newInstance(consumer.getClass(), numberOfObservers);
}

public void addConsumer(int consumerIndex, BiConsumer<Integer, X> consumer) {
    // Offending line
    fieldConsumers[consumerIndex] = responseType-> consumer.accept(responseType, fieldSubject);

}

以便可以通过以下方式触发回调:

for (Consumer<Integer> consumer: fieldConsumers) {
    consumer.accept(responseType);
}

我收到错误:

java.lang.ArrayStoreException:

在这一行:

fieldConsumers[consumerIndex] = responseType-> consumer.accept(responseType, fieldSubject);

现在,如果您仍在阅读本文,我还有一个问题:

如果我这样做,我是否仍然保留对外部消费者的引用,而不是使用旧的 fieldConsumers.add(consumer)其中 fieldConsumers 是 List<BiConsumer<Integer, X>>

最佳答案

您使用了Array.newInstance(consumer.getClass(), numberOfObservers)创建Consumer<Integer>[]大批。但是consumer.getClass()返回您调用方法的对象的实际类,该类始终是接口(interface)的实现类。这种元素类型的数组只能保存同一具体类的对象,而不能保存该接口(interface)的任意实现。

这与例如没有什么不同

CharSequence cs = "hello";
CharSequence[] array = (CharSequence[]) Array.newInstance(cs.getClass(), 1);
array[0] = new StringBuilder();

在这里,cs类型为 CharSequence并且反射数组创建似乎创建了 CharSequence[] 类型的数组,因此存储 StringBuilder应该是可能的。但自从 cs.getClass()返回实际的实现类String ,该数组实际上是 String[] 类型,因此,尝试存储 StringBuilder产生 ArrayStoreException .

对于 lambda 表达式,事情会变得稍微复杂一些,因为函数接口(interface)的实际实现类是在运行时提供的,并且有意未指定。您使用了 lambda 表达式 integer -> {}对于构造函数中的数组创建,其计算结果为与 responseType-> consumer.accept(responseType, fieldSubject) 不同的实现类addConsumer内方法,在这个特定的运行时

此行为符合 this answer描述最常用环境的行为。尽管如此,其他实现可能会表现出不同的行为,例如对于所有 lambda 表达式,特定函数接口(interface)的计算结果为相同的实现类。但同一 lambda 表达式的多次计算也可能会产生不同的类。

因此解决方法是使用预期的界面元素类型,例如

fieldConsumers=(Consumer<Integer>[])Array.newInstance(Consumer.class, numberOfObservers);

但是根本不需要创建反射数组。您可以使用:

fieldConsumers = new Consumer[numberOfObservers];

你不能写new Consumer<Integer>[numberOfObservers] ,因为不允许创建通用数组。这就是上面的代码使用原始类型的原因。使用反射并不能改善这种情况,因为在任何情况下它都是未经检查的操作。您可能需要添加 @SuppressWarnings为了它。更干净的替代方案是使用 List<Consumer<Integer>> ,因为它可以让您免受数组和泛型的奇怪影响。

不清楚您在这里所说的“引用外部消费者”是什么意思。无论哪种情况,您都可以引用 Consumer捕获对BiConsumer的引用的实现您收到的作为 addConsumer 参数的实现.

关于java - Consumers<X> 数组中的 ArrayStoreException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64295745/

相关文章:

xml - 如何控制 XML 中元素之间的引用

java - 使用最新的 Jetty 和 Jersey 在上传到 Heroku 的 WAR 文件中找不到依赖类

java - 为什么 statet eclipse 插件在使用 java 1.7.0 更新环境索引时崩溃?

javascript - 在交替的正方形中填充二维数组

javascript - 将数组转换为带有子对象的对象

c++ - 右值的生命周期绑定(bind)到静态常量引用

.net - F# 处理值和引用

java - 玩简单的 Java 游戏时遇到问题

java - 键绑定(bind)问题

c++ - 数组得到的比它应该的多