【问题标题】:Java lambda type with generics [duplicate]具有泛型的Java lambda类型[重复]
【发布时间】:2016-12-26 04:06:52
【问题描述】:

当下面的代码运行时:

import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;

class A {
    private static final List<Adapter<? extends Number>> adapters = Arrays.asList(
            Integer::valueOf,
            s -> Long.valueOf(s),
            (Adapter<Float>) s -> Float.valueOf(s),
            new Adapter<Double>() {
                @Override
                public Double adapt(String s) {
                    return Double.valueOf(s);
                }
            }
    );

    private interface Adapter<T> {
        T adapt(String s);

        default Type type() {
            try {
                return getClass().getMethod("adapt", String.class).getReturnType();
            } catch (NoSuchMethodException e) {
                throw new AssertionError(e);
            }
        }
    }

    public static void main(String[] args) {
        for (Adapter<?> adapter : adapters) {
            System.out.printf("Got adapter for type %s%n",
                    adapter.type().getTypeName());
        }
    }
}

我明白了:

% javac A.java
% java -version
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
% java A
Got adapter for type java.lang.Object
Got adapter for type java.lang.Object
Got adapter for type java.lang.Object
Got adapter for type java.lang.Double

我很好奇为什么只有最后一个适配器被识别为 Double,其余的是 Object(而不是 Integer、Long 和 Float)。至少,我预计他们会支持 Number。

【问题讨论】:

  • 有趣的问题...可能与编译器捕获泛型类型的方式有关。
  • 查找这个的地方是在 JLS。希望这里有人知道从哪里引用。

标签: java generics lambda java-8


【解决方案1】:
        new Adapter<Double>() {
            @Override
            public Double adapt(String s) {
                return Double.valueOf(s);
            }
        }

上面的代码会为Adapter接口创建一个实现类,编译后可以看到:A$1.class在你的目录下,这是new Adapter的实现类。您可以使用javap -c A\$1 来检查bytecode,例如:

Compiled from "A.java"
final class A$1 implements A$Adapter<java.lang.Double> {
  A$1();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public java.lang.Double adapt(java.lang.String);
    Code:
       0: aload_1
       1: invokestatic  #2                  // Method java/lang/Double.valueOf:(Ljava/lang/String;)Ljava/lang/Double;
       4: areturn

  public java.lang.Object adapt(java.lang.String);
    Code:
       0: aload_0
       1: aload_1
       2: invokevirtual #3                  // Method adapt:(Ljava/lang/String;)Ljava/lang/Double;
       5: areturn
}

如您所见,A$1.adapt 类已通过编译器推断出Double 类型。

而对于Lambda expression,编译器只是将其处理为invokedynamic #2, 0 // InvokeDynamic #0:adapt:()LA$Adapter;,所以由于类型擦除,这将是Object类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 1970-01-01
    相关资源
    最近更新 更多