获取lambdas类的列表

时间:2014-05-11 16:33:04

标签: java lambda java-8

在Java 8中,看起来类的lambda保存在数组中。例如,假设我们有这个类:

public class LambdaFactory {
    public Supplier<Integer> getOne(){
        return () -> 42;
    }

    public Supplier<Integer> getTwo(){
        return () -> 128;
    }

    public Supplier<Integer> getThree(){
         return () -> 3;
    }
}

然后我这样打印出来:

    System.out.println(factory.getOne());
    System.out.println(factory.getOne());
    System.out.println(factory.getTwo());
    System.out.println(factory.getThree());

输出将类似于

examples.LambdaFactory$$Lambda$1@4e515669
examples.LambdaFactory$$Lambda$1@4e515669
examples.LambdaFactory$$Lambda$2@1b9e1916
examples.LambdaFactory$$Lambda$3@ba8a1dc

所以我们在这里可以看到两件事。两次调用的lambda给了我们相同的lambda对象(这与我们每次都可以得到一个新的内部类不同)。我们也看到它们看起来像是被保留在某种“Lambda”结构中,而这种结构是该类的一部分

我的问题是,我可以在课堂上看到lambdas吗?我没有任何理由这样做,我只是想解剖一些事情

2 个答案:

答案 0 :(得分:10)

lambda是由JRE创建的,它们的创建方式由JRE控制,可能因不同的JRE供应商而异,并且可能在将来的版本中有所改变。

如果你想玩得开心,你可以在运行时创建一个lambda,它在类文件中没有相应的信息:

import java.lang.invoke.*;

public class ManualLambda {
  public static void main(String[] args) throws Throwable {
    MethodHandles.Lookup me=MethodHandles.lookup();
    MethodType t=MethodType.methodType(void.class);
    MethodType rt=MethodType.methodType(Runnable.class);
    CallSite site = LambdaMetafactory.metafactory(
      me, "run", rt, t, me.findStatic(ManualLambda.class, "sayHello", t), t);
    MethodHandle factory=site.getTarget();
    Runnable r=(Runnable)factory.invoke();

    System.out.println("created lambda: "+r);
    r.run();
  }
  private static void sayHello() {
      System.out.println("hello world");
  }
}

上面的代码回顾了创建lambda时发生的事情。但对于编译时(“实际”)lambda表达式,整个事物由单个invokedynamic字节代码指令触发。 LambdaMetafactory.metafactory(…)方法是 bootstrap 方法,在第一次执行invokedynamic指令时调用该方法。返回的CallSite对象与invokedynamic指令永久关联。如果CallSiteConstantCallSite并且其MethodHandle在每次执行时都返回相同的lambda对象,则invokedynamic指令将永久“生成”相同的lambda实例。

答案 1 :(得分:2)

The Java Language Specification states

  

在运行时,lambda表达式的评估类似于   在正常情况下评估类实例创建表达式   完成生成对象的引用。 [...]

     

具有以下属性的类的新实例是   已分配和初始化,或具有该类的现有实例   以下属性被引用。

     

[...]

     

这些规则旨在为实施提供灵活性   Java编程语言,在:

     
      
  • 无需在每次评估时分配新对象。
  •   
  • [...]
  •   

因此,在编译lambda表达式时,由编译器或运行时环境决定应该返回什么。

  

我的问题是,我可以在课堂上看到lambdas吗?我不   有任何理由这样做,我只是喜欢解剖事物

你可以认为一个lambda表达式作为任何其他类常量,String,整数文字等。这些是出现在{{1的常量池中的常量文件。这些是对在运行时创建和存在的对象的引用。无法从类的常量池中引用实际对象。

在lambda的情况下,它无论如何都没有用,因为它实际上可能不是同一个对象。