LambdaMetafactory类的用法以及使用场景

介绍

介绍:
LambdaMetafactory类是Java内部实现Lambda表达式的关键。通过LambdaMetafactory,Java编译器可以将Lambda表达式转化为内部匿名类。
Lambda表达式本质上是编译器语法糖,在运行时会变成内部匿名类。LambdaMetafactory的作用就是实现这个转化过程。
使用场景:
当我们在代码中使用Lambda表达式时,编译器会利用LambdaMetafactory将Lambda表达式转换为内部匿名类

LambdaMetafactory类主要包含三个方法:

  • metafactory:用于将有多个参数的Lambda表达式转化为内部匿名类。它会返回一个CallSite对象代表转化后的表达式。
  • altMetafactory:用于将没有参数或者只有一个参数的Lambda表达式转化为内部匿名类。它也会返回一个CallSite对象。
  • defaultCallSite:返回一个默认的CallSite对象。当无法准确转化Lambda表达式时,会调用这个方法返回默认对象,以避免异常。

这三个方法都是Lambda表达式转化过程的关键,编译器会自动选择合适的方法将我们编写的Lambda表达式映射到内部匿名类,然后返回代表这个表达式的CallSite对象。

LambdaMetafactory的使用场景主要有:

  1. 在我们使用Lambda表达式时,编译器会利用LambdaMetafactory类完成表达式到内部匿名类的转化。这是LambdaMetafactory的主要使用场景,它是实现Lambda表达式的基础。
  2. 当无法准确地将Lambda表达式转化时,会调用defaultCallSite方法返回一个默认CallSite对象,以保证方法的正常执行。这属于异常场景,主要是考虑到转化的健壮性。
  3. 在需要深入理解Lambda表达式原理时,可以研究LambdaMetafactory类的源码。通过观察它是如何完成Lambda表达式到内部匿名类的映射,我们可以更加全面地理解Lambda的工作机制。这属于更高级的使用场景。

所以LambdaMetafactory的使用从两方面来说:

一方面:
它的使用对我们来说是透明的,在我们使用Lambda表达式时,编译器会自动调用相应的方法。这属于LambdaMetafactory的基本使用。
另一方面:
理解LambdaMetafactory的原理和实现机制,有助于我们深入研究Lambda表达式背后复杂的工作过程。这属于更高级的使用,主要面向精通Java和Java编译原理的开发者。

总结:总的来说,LambdaMetafactory是实现Lambda表达式的关键,它的存在使我们可以轻松地在代码中使用Lambda。同时,理解这个类也让我们有机会深入学习Java8中引入的重要特性——Lambda表达式。

metafactory方法的使用

metafactory方法是LambdaMetafactory类中最重要的方法之一。它的作用是将有多个参数的Lambda表达式转化为内部匿名类。

其方法签名是:

public static CallSite metafactory(MethodHandles.Lookup caller, 
                                   String invokedName, 
                                   MethodType invokedType, 
                                   MethodType samMethodType, 
                                   MethodHandle implMethod, 
                                   MethodType instantiatedMethodType)  

参数说明:

  • caller:方法查找对象,用于检查权限
  • invokedName:表示Lambda表达式调用的方法名
  • invokedType:表示Lambda表达式的类型
  • samMethodType:表示函数式接口中的抽象方法类型
  • implMethod:表示Lambda表达式要代替的方法句柄
  • instantiatedMethodType:表示内部匿名类要实现的接口类型
    该方法会返回一个CallSite对象,代表Lambda表达式的调用点。

例如,我们有这样一个Lambda表达式:

//该表达式的类型是(int, int) -> int,要代替的方法是int x(int, int)。
(x, y) -> x + y 

通过metafactory方法,这个Lambda表达式会被转化为:

new I() {
    
    
   public int m(int x, int y) {
    
    
     return x + y; 
   } 
}

I是函数式接口,m是接口中的抽象方法。

转换的主要步骤是:

  1. 获取Lambda表达式的类型(invokedType)和要实现的接口类型(instantiatedMethodType)
  2. 获取要代替的方法句柄(implMethod)
  3. 创建一个CallSite对象,它代表Lambda表达式的调用点
  4. CallSite内部会创建一个内部匿名类,并重写对应的抽象方法
  5. 将CallSite对象返回,该对象就代表转化后的Lambda表达式

所以通过metafactory方法,编译器可以将有多个参数的Lambda表达式转化为内部匿名类。这是实现Lambda表达式的关键,我们在使用Lambda表达式时就已经隐式地利用到了这个方法。
理解metafactory的原理,可以让我们更深入地了解Lambda表达式的工作机制。尽管在日常使用中不需要直接接触这个方法,但是作为Java开发者,了解Lambda表达式背后的原理还是很有帮助的。

altMetafactory方法的使用

altMetafactory方法是LambdaMetafactory类中另一个重要的方法。它的作用是将没有参数或者只有一个参数的Lambda表达式转化为内部匿名类。

其方法签名是:

public static CallSite altMetafactory(MethodHandles.Lookup caller, 
                                    String invokedName, 
                                    MethodType invokedType,  
                                    Object... invokedExactArgs) 

参数说明:

  • caller:方法查找对象,用于检查权限
  • invokedName:表示Lambda表达式调用的方法名
  • invokedType:表示Lambda表达式的类型
  • invokedExactArgs:表示Lambda表达式的参数列表

该方法会返回一个CallSite对象,代表Lambda表达式的调用点。

例如,我们有这样一个Lambda表达式:

() -> System.out.println("Hello")
//该表达式的类型是() -> void,没有参数。

通过altMetafactory方法,这个Lambda表达式会被转化为:

new I() {
    
    
   public void m() {
    
    
     System.out.println("Hello");
   }
} 

I是函数式接口,m是接口中的抽象方法。

转换的主要步骤是:

  1. 获取Lambda表达式的类型(invokedType)
  2. 创建一个CallSite对象,它代表Lambda表达式的调用点
  3. CallSite内部会创建一个内部匿名类,并重写对应的抽象方法
  4. 将CallSite对象返回,该对象就代表转化后的Lambda表达式

所以通过altMetafactory方法,编译器可以将没有参数或者只有一个参数的Lambda表达式转化为内部匿名类。这也是实现Lambda表达式的关键所在。
和metafactory方法一样,altMetafactory也是Lambda表达式转化过程中重要的一环,它专门处理简单Lambda表达式的转化。理解这个方法的原理,可以让我们全面地掌握Lambda表达式的工作机制,尽管我们在日常编程中并不需要直接使用。
Lambda表达式是Java8中引入的重要特性,要真正掌握Lambda,必须对背后的原理有深入的理解。altMetafactory和metafactory是实现Lambda的两个关键方法,它们配合编译器完成从Lambda表达式到内部匿名类的转化过程。

defaultCallSite方法的使用

defaultCallSite方法是LambdaMetafactory类中的另一个方法。它的作用是返回一个默认的CallSite对象。

其方法签名是:

public static CallSite defaultCallSite(MethodHandles.Lookup caller, 
                                      String invokedName, 
                                      MethodType invokedType)

参数说明:

  • caller:方法查找对象,用于检查权限
  • invokedName:表示Lambda表达式调用的方法名
  • invokedType:表示Lambda表达式的类型

该方法会返回一个默认的CallSite对象。

当通过LambdaMetafactory类无法准确地将Lambda表达式转化为内部匿名类时,就会使用这个defaultCallSite方法返回一个默认的CallSite对象。这个默认对象并不会像metafactory和altMetafactory方法那样,转化为一个精确匹配的内部匿名类。
它的作用主要是为了保证LambdaMetafactory类的方法在所有情况下都有所返回,不会出现NullPointerException等异常。但是返回的CallSite对象可能并不精确地表示程序员编写的Lambda表达式。

例如,我们有这样一个Lambda表达式:

(x, y) -> x + y 

如果通过metafactory方法无法准确地将其转化为内部匿名类,就会调用defaultCallSite方法,返回一个默认的CallSite对象。
这个对象并不代表(x, y) -> x + y这个Lambda表达式,但是可以避免出现异常。
所以,defaultCallSite方法的主要作用是在Lambda表达式转化失败的情况下,返回一个默认值以保证方法的正常执行。
它并不会像metafactory和altMetafactory方法那样,精确地将Lambda表达式映射到内部匿名类。
它的存在主要是出于对异常情况的考虑,保证LambdaMetafactory类的方法在任何情况下都有一定的返回值。但是返回的CallSite对象并不一定精确代表程序员编写的Lambda表达式,这点需要在使用时注意。

在理解LambdaMetafactory类的使用时,也应该了解defaultCallSite方法。尽管我们在日常编程中不会直接使用它,但是它是Lambda表达式转化机制的一部分,其存在说明了Java在这方面对异常情况的考虑。理解这个方法有助于我们全面地了解Lambda表达式的实现原理。

猜你喜欢

转载自blog.csdn.net/qq_25000135/article/details/130150512
今日推荐