转换Java功能接口 [英] Casting Java functional interfaces
问题描述
和往常一样,我一直在浏览JDK 8源代码,并发现了非常有趣的代码:
As always I was looking through JDK 8 sources and found very interesting code:
@Override
default void forEachRemaining(Consumer<? super Integer> action) {
if (action instanceof IntConsumer) {
forEachRemaining((IntConsumer) action);
}
}
问题是: Consumer<怎么样?super Integer>
可以是 IntConsumer
的实例吗?因为它们处于不同的层次结构.
The question is: how Consumer<? super Integer>
could be an instance of IntConsumer
? Because they are in different hierarchy.
我制作了类似的代码段来测试投放:
I have made similar code snippet to test casting:
public class InterfaceExample {
public static void main(String[] args) {
IntConsumer intConsumer = i -> { };
Consumer<Integer> a = (Consumer<Integer>) intConsumer;
a.accept(123);
}
}
但是它会抛出 ClassCastException
:
Exception in thread "main"
java.lang.ClassCastException:
com.example.InterfaceExample$$Lambda$1/764977973
cannot be cast to
java.util.function.Consumer
您可以在推荐答案
让我们看看下面的代码,那么您可以看到原因了吗? Let's see the code below, then you can see why? 任何类都可以实现多个接口,一个可以是 Any class can implement multi-interfaces, one is 注意:这是 之后,您可以将 THEN you can use 我发现如果通过诸如 I found it why need to cast a 一个原因是,当我们使用 One reason is when we use a 另一个原因是重用了一段代码. OfInt#forEachRemaining(Consumer)是应用 OfInt#forEachRenaming(IntConsumer). Another reason is reusing a piece of code. The body of OfInt#forEachRemaining(Consumer) is a good example of applying Adapter Design Pattern for reusing OfInt#forEachRenaming(IntConsumer). 这篇关于转换Java功能接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!class IntegerConsumer implements Consumer<Integer>, IntConsumer {
...
}
Consumer< Integer>
,或者可以实现另一个可以是 IntConsumer
.当我们想使 IntConsumer
适应 Consumer< Integer>
并保存其原始类型( IntConsumer
)时,有时会出现这种情况,代码看起来像下方:Consumer<Integer>
maybe implements another one is IntConsumer
. Sometimes occurs when we want to adapt IntConsumer
to Consumer<Integer>
and to save its origin type (IntConsumer
), then the code looks like as below:class IntConsumerAdapter implements Consumer<Integer>, IntConsumer {
@Override
public void accept(Integer value) {
accept(value.intValue());
}
@Override
public void accept(int value) {
// todo
}
}
IntConsumerAdapter
用作 Consumer< Integer>
和 IntConsumer
,例如:>IntConsumerAdapter
both as Consumer<Integer>
and IntConsumer
, for example:Consumer<? extends Integer> consumer1 = new IntConsumerAdapter();
IntConsumer consumer2 = new IntConsumerAdapter();
Sink.OfInt
is a concrete usage of Class Adapter Design Pattern in jdk-8.The downside of Sink.OfInt#accept(Integer)
is clearly that JVM will throw a NullPointerException
when it accepts a null
value, so that is why Sink
is package visible.189 interface OfInt extends Sink<Integer>, IntConsumer {
190 @Override
191 void accept(int value);
193 @Override
194 default void accept(Integer i) {
195 if (Tripwire.ENABLED)
196 Tripwire.trip(getClass(), "{0} calling Sink.OfInt.accept(Integer)");
197 accept(i.intValue());
198 }
199 } IntConsumerAdapter
之类的使用者,为什么需要将 Consumer< Integer>
强制转换为 IntConsumer
?Consumer<Integer>
to an IntConsumer
if pass a consumer like as IntConsumerAdapter
? Consumer
接受 int
时,编译器需要将其自动装箱到 Integer
.在方法 accept(Integer)
中,您需要手动将 Integer
装箱到 int
.换句话说,每个 accept(Integer)
都执行2个用于装箱/拆箱的附加操作.它需要提高性能,因此需要在算法库中进行一些特殊检查.Consumer
to accept an int
the compiler needs to auto-boxing it to an Integer
. And in the method accept(Integer)
you need to unbox an Integer
to an int
manually.
In the other words, each accept(Integer)
does 2 additional operations for boxing/unboxing. It needs to improve the performance so it does some special checking in the algorithm library.default void forEachRemaining(Consumer<? super Integer> action) {
if (action instanceof IntConsumer) {
// action's implementation is an example of Class Adapter Design Pattern
// |
forEachRemaining((IntConsumer) action);
}
else {
// method reference expression is an example of Object Adapter Design Pattern
// |
forEachRemaining((IntConsumer) action::accept);
}
}