转换Java功能接口 [英] Casting Java functional interfaces

查看:76
本文介绍了转换Java功能接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

和往常一样,我一直在浏览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?

class IntegerConsumer implements Consumer<Integer>, IntConsumer {
   ...
}

任何类都可以实现多个接口,一个可以是 Consumer< Integer> ,或者可以实现另一个可以是 IntConsumer .当我们想使 IntConsumer 适应 Consumer< Integer> 并保存其原始类型( IntConsumer )时,有时会出现这种情况,代码看起来像下方:

Any class can implement multi-interfaces, one is 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 ,例如:

THEN you can use IntConsumerAdapter both as Consumer<Integer> and IntConsumer, for example:

Consumer<? extends Integer> consumer1 = new IntConsumerAdapter();
IntConsumer consumer2 = new IntConsumerAdapter();

Sink.OfInt

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 ?

I found it why need to cast a Consumer<Integer> to an IntConsumer if pass a consumer like as IntConsumerAdapter?

一个原因是,当我们使用 Consumer 接受 int 时,编译器需要将其自动装箱到 Integer .在方法 accept(Integer)中,您需要手动将 Integer 装箱到 int .换句话说,每个 accept(Integer)都执行2个用于装箱/拆箱的附加操作.它需要提高性能,因此需要在算法库中进行一些特殊检查.

One reason is when we use a 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.

另一个原因是重用了一段代码. OfInt#forEachRemaining(Consumer)是应用

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).

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

这篇关于转换Java功能接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆