我正在存储对 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/