消费者数组中的 ArrayStoreException<X>
ArrayStoreException in array of Consumers<X>
我正在存储对 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()
returns 您正在调用该方法的对象的实际 class,它始终是 实现 class界面。这种元素类型的数组只能容纳相同具体的对象 class,不能容纳接口的任意实现。
这与例如
没有什么不同
CharSequence cs = "hello";
CharSequence[] array = (CharSequence[]) Array.newInstance(cs.getClass(), 1);
array[0] = new StringBuilder();
此处,cs
的类型为 CharSequence
,反射数组创建似乎创建了一个类型为 CharSequence[]
的数组,因此存储 StringBuilder
应该是可能的。但是由于 cs.getClass()
returns 实际实现 class String
,数组实际上是 String[]
类型,因此,尝试存储 StringBuilder
产生一个 ArrayStoreException
.
在 lambda 表达式的情况下,事情会稍微复杂一些,因为功能接口的实际实现 classes 在运行时提供并且有意未指定。您在构造函数中使用了 lambda 表达式 integer -> {}
来创建数组,它的计算结果 class 与 addConsumer
方法中的 responseType-> consumer.accept(responseType, fieldSubject)
不同在这个特定的运行时.
此行为符合 this answer 描述最常用环境的行为。尽管如此,其他实现可能会表现出不同的行为,例如对于所有 lambda 表达式的特定功能接口,评估为相同的实现 class。但也有可能对同一个 lambda 表达式的多次求值产生不同的 classes.
所以解决方法是使用预期的界面元素类型,例如
fieldConsumers=(Consumer<Integer>[])Array.newInstance(Consumer.class, numberOfObservers);
但是根本不需要创建反射数组。您可以使用:
fieldConsumers = new Consumer[numberOfObservers];
您不能写 new Consumer<Integer>[numberOfObservers]
,因为不允许创建通用数组。这就是为什么上面的代码使用原始类型。使用反射不会改善这种情况,因为在任何一种情况下它都是未经检查的操作。您可能需要为其添加 @SuppressWarnings
。更简洁的替代方法是使用 List<Consumer<Integer>>
,因为它使您免受数组和泛型的怪异影响。
不清楚您在这里所说的“参考外部消费者”是什么意思。在任何一种情况下,您都有对 Consumer
实现的引用捕获对 BiConsumer
实现的引用,这些实现是作为 addConsumer
.
的参数收到的
我正在存储对 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()
returns 您正在调用该方法的对象的实际 class,它始终是 实现 class界面。这种元素类型的数组只能容纳相同具体的对象 class,不能容纳接口的任意实现。
这与例如
没有什么不同CharSequence cs = "hello";
CharSequence[] array = (CharSequence[]) Array.newInstance(cs.getClass(), 1);
array[0] = new StringBuilder();
此处,cs
的类型为 CharSequence
,反射数组创建似乎创建了一个类型为 CharSequence[]
的数组,因此存储 StringBuilder
应该是可能的。但是由于 cs.getClass()
returns 实际实现 class String
,数组实际上是 String[]
类型,因此,尝试存储 StringBuilder
产生一个 ArrayStoreException
.
在 lambda 表达式的情况下,事情会稍微复杂一些,因为功能接口的实际实现 classes 在运行时提供并且有意未指定。您在构造函数中使用了 lambda 表达式 integer -> {}
来创建数组,它的计算结果 class 与 addConsumer
方法中的 responseType-> consumer.accept(responseType, fieldSubject)
不同在这个特定的运行时.
此行为符合 this answer 描述最常用环境的行为。尽管如此,其他实现可能会表现出不同的行为,例如对于所有 lambda 表达式的特定功能接口,评估为相同的实现 class。但也有可能对同一个 lambda 表达式的多次求值产生不同的 classes.
所以解决方法是使用预期的界面元素类型,例如
fieldConsumers=(Consumer<Integer>[])Array.newInstance(Consumer.class, numberOfObservers);
但是根本不需要创建反射数组。您可以使用:
fieldConsumers = new Consumer[numberOfObservers];
您不能写 new Consumer<Integer>[numberOfObservers]
,因为不允许创建通用数组。这就是为什么上面的代码使用原始类型。使用反射不会改善这种情况,因为在任何一种情况下它都是未经检查的操作。您可能需要为其添加 @SuppressWarnings
。更简洁的替代方法是使用 List<Consumer<Integer>>
,因为它使您免受数组和泛型的怪异影响。
不清楚您在这里所说的“参考外部消费者”是什么意思。在任何一种情况下,您都有对 Consumer
实现的引用捕获对 BiConsumer
实现的引用,这些实现是作为 addConsumer
.