Module  java.base
软件包  java.lang.invoke

Class MethodHandle



  • public abstract class MethodHandle
    extends Object
    方法句柄是一个类型化的,直接可执行的对底层方法,构造函数,字段或类似低级操作的引用,具有参数或返回值的可选转换。 这些转换是相当普遍的,并且包括这样的模式为conversioninsertiondeletion ,并substitution

    方法句柄内容

    根据其参数和返回类型,方法句柄是动态和强类型的。 它们不被其基础方法的名称或定义类区分。 必须使用与方法句柄自己的type descriptor相匹配的符号类型描述符来调用方法句柄。

    每个方法句柄通过type访问器报告其类型描述符。 该类型描述符是一个MethodType对象,其结构是一系列类,其中一个是方法的返回类型(如果没有, void.class )。

    方法句柄的类型控制它接受的调用类型,以及适用于它的转换种类。

    方法句柄包含一对称为invokeExactinvoke的特殊调用方法。 这两个调用方法都可以直接访问方法句柄的底层方法,构造函数,字段或其他操作,通过参数和返回值的转换进行修改。 两个调用者接受与方法句柄自己的类型完全匹配的调用。 普通的,不精确的调用者也接受一系列其他呼叫类型。

    方法句柄是不可变的,没有可见状态。 当然,它们可以绑定到显示状态的底层方法或数据。 对于Java内存模型,任何方法句柄的行为就好像它的所有(内部)字段都是最终变量。 这意味着对应用程序可见的任何方法句柄将始终完全形成。 即使在数据竞赛中通过共享变量发布方法句柄也是如此。

    方法句柄不能被用户子类化。 实现可能(或可能不)创建MethodHandle内部子类,这可以通过Object.getClass操作看到。 程序员不应该从其特定的类中得出关于方法句柄的结论,因为方法句柄类层次结构(如果有的话)可能会不时地或跨不同供应商的实现发生变化。

    方法句柄编译

    命名为invokeExactinvoke Java方法调用表达式可以从Java源代码调用方法句柄。 从源代码的角度来看,这些方法可以接受任何参数,并将其结果转换为任何返回类型。 正式地,这是通过给出调用方法Object返回类型和变量arity Object参数来实现的,但是它们具有称为签名多态性的附加质量,其将该调用自由直接连接到JVM执行堆栈。

    像虚拟方法一样,源级调用invokeExactinvoke编译为一个invokevirtual指令。 更奇怪的是,编译器必须记录实际的参数类型,并且可能不会对参数执行方法调用转换。 相反,它必须根据自己的未转换类型生成将它们推送到堆栈的指令。 方法handle对象本身被推送到栈前的参数。 然后,编译器将生成一个invokevirtual指令,该指令用描述参数和返回类型的符号类型描述符调用方法句柄。

    要发出完整的符号类型描述符,编译器还必须确定返回类型。 这是基于对方法调用表达一个演员,如果有,否则Object如果调用是一个表达式,否则void如果调用的声明。 演员可能是原始类型(但不是void )。

    为角情况下,uncasted null给出参数的象征性类型描述符java.lang.Void 与类型Void的歧义是无害的,因为没有引用类型Void除了空引用。

    方法句柄调用

    第一次执行invokevirtual指令时,它通过符号解析指令中的名称并验证方法调用是静态合法的。 这也适用于拨打invokeExactinvoke 在这种情况下,检查编译器发出的符号类型描述符是否正确的语法,并且解析其包含的名称。 因此,只要符号类型描述符在语法上形成良好并且类型存在,则调用方法句柄的invokevirtual指令将始终链接。

    当链接后执行invokevirtual ,接收方法句柄的类型首先由JVM检查,以确保它符合符号类型描述符。 如果类型匹配失败,则意味着调用者调用的方法不会在被调用的单个方法句柄上显示。

    invokeExact的情况下,调用的类型描述符(解析符号类型名称后)必须与接收方法句柄的方法类型完全匹配。 在普通的情况下,不精确的invoke ,解析的类型描述符必须是接收方的asType方法的有效参数。 因此,平原invokeinvokeExactinvokeExact

    类型匹配后,直接调用invokeExact并立即调用方法句柄的底层方法(或其他行为,视情况而定)。

    如果调用者指定的符号类型描述符与方法句柄自己的类型完全匹配,则调用plain invoke工作方式与调用invokeExact相同。 如果有类型不匹配, invoke尝试调整接收方法句柄的类型,好像通过调用asType ,以获得一个精确可调用的方法句柄M2 这允许在调用者和被调用者之间进行更强大的方法类型协商。

    注意:调整后的方法句柄M2是不可直接观察到的,因此实现不需要实现。)

    调用检查

    在典型的程序中,方法句柄类型匹配通常会成功。 但是,如果地址不匹配时,JVM将抛出一个WrongMethodTypeException ,直接(在的情况下invokeExact )或间接仿佛被一个失败的调用asType (在的情况下invoke )。

    因此,在静态类型程序中可能显示为链接错误的方法类型不匹配可以在使用方法句柄的程序中显示为动态的WrongMethodTypeException

    由于方法类型包含“live” Class对象,方法类型匹配同时考虑了类型名称和类加载器。 因此,即使一个方法手柄M在一个类加载器创建L1和使用另一L2 ,方法句柄调用是类型安全的,因为调用者的符号类型描述符,如解决L2 ,与最初的被叫方法的符号类型匹配描述符,解决于L1 决议L1时发生M被创建,其类型分配,而在分辨率L2当发生invokevirtual指令链接。

    除了类型描述符检查,方法句柄调用其底层方法的能力是不受限制的。 如果方法句柄是通过访问该方法的类在非公共方法上形成的,那么生成的句柄可以由任何接收到它的引用的调用者在任何地方使用。

    与Core Reflection API不同,每次调用反射方法时都会检查访问权限,因此执行方法句柄访问检查when the method handle is created ldc (见下文)的情况下,访问检查作为链接恒定方法句柄下的常量池条目的一部分执行。

    因此,非公共方法的处理方式或非公共类的方法一般应保密。 它们不应该传递给不受信任的代码,除非它们来自不受信任的代码的使用将是无害的。

    方法句柄创建

    Java代码可以创建一个方法句柄,直接访问该代码可访问的任何方法,构造函数或字段。 这是通过一个反映出基于能力的API MethodHandles.Lookup完成的 例如,静态方法句柄可以从Lookup.findStatic获得。 还有Core Reflection API对象的转换方法,如Lookup.unreflect

    像类和字符串一样,对应于可访问字段,方法和构造函数的方法句柄也可以直接在类文件的常量池中表示为要由ldc字节码加载的ldc 一种新型的常量存储库项,的CONSTANT_MethodHandle ,直接指的是相关的CONSTANT_MethodrefCONSTANT_InterfaceMethodref ,或CONSTANT_Fieldref常量存储库项。 (有关方法句柄常量的详细信息,请参阅Java虚拟机规范的第4.4.8和5.4.3.5节。)

    通过查找方法或通过具有变量arity修饰符位( 0x0080 )的方法或构造函数产生的方法句柄具有相应的变量特征,就像在asVarargsCollectorwithVarargs的帮助下定义一样

    方法引用可以指静态方法或非静态方法。 在非静态情况下,方法句柄类型包括一个显式的接收器参数,在任何其他参数之前。 在方法句柄的类型中,初始的接收者参数根据初始请求方法的类来键入。 (例如,如果通过ldc获得非静态方法句柄,则接收器的类型是在常量池条目中命名的类。)

    方法句柄常量受到相同的链接时间访问检查其对应的字节码指令,如果字节码行为将抛出此类错误,则ldc指令将抛出相应的链接错误。

    作为其推论,对受保护成员的访问仅限于访问类或其子类之一的接收者,而访问类又必须是受保护成员的定义类的子类(或包兄弟)。 如果方法引用是指当前包以外的类的受保护的非静态方法或字段,则接收方参数将被缩小为访问类的类型。

    当调用一个虚拟方法的方法句柄时,方法总是在接收器中查找(也就是第一个参数)。

    也可以创建特定虚拟方法实现的非虚拟方法句柄。 这些不执行基于接收器类型的虚拟查找。 这种方法句柄可以模拟invokespecial指令对同一方法的影响。

    用法示例

    以下是一些使用示例:
    
    Object x, y; String s; int i;
    MethodType mt; MethodHandle mh;
    MethodHandles.Lookup lookup = MethodHandles.lookup();
    // mt is (char,char)String
    mt = MethodType.methodType(String.class, char.class, char.class);
    mh = lookup.findVirtual(String.class, "replace", mt);
    s = (String) mh.invokeExact("daddy",'d','n');
    // invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
    assertEquals(s, "nanny");
    // weakly typed invocation (using MHs.invoke)
    s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
    assertEquals(s, "savvy");
    // mt is (Object[])List
    mt = MethodType.methodType(java.util.List.class, Object[].class);
    mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
    assert(mh.isVarargsCollector());
    x = mh.invoke("one", "two");
    // invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
    assertEquals(x, java.util.Arrays.asList("one","two"));
    // mt is (Object,Object,Object)Object
    mt = MethodType.genericMethodType(3);
    mh = mh.asType(mt);
    x = mh.invokeExact((Object)1, (Object)2, (Object)3);
    // invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
    assertEquals(x, java.util.Arrays.asList(1,2,3));
    // mt is ()int
    mt = MethodType.methodType(int.class);
    mh = lookup.findVirtual(java.util.List.class, "size", mt);
    i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
    // invokeExact(Ljava/util/List;)I
    assert(i == 3);
    mt = MethodType.methodType(void.class, String.class);
    mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
    mh.invokeExact(System.out, "Hello, world.");
    // invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V
     
    以上对invokeExact或普通的invoke每个调用生成一个带有下列注释中指示的符号类型描述符的单个invoke指令。 在这些示例中,辅助方法assertEquals被假定为在其参数上调用Objects.equals的方法,并且断言结果为真。

    例外

    方法invokeExactinvoke被声明为抛出Throwable ,这就是说方法句柄可以抛出什么没有静态限制。 由于JVM不区分被检查和未检查的异常(当然,除了它们的类之外),因此将检查的异常归因于方法句柄调用对字节码形状没有特别的影响。 但是在Java源代码中,执行方法处理调用的方法必须明确地抛出Throwable ,否则必须在本地捕获所有可抛出的值,重新抛出仅在上下文中合法的那些,并且包装非法的那些。

    签名多态性

    invokeExact和普通的invoke的异常编译和链接行为由术语签名多态性引用。 如Java语言规范中定义的,签名多态方法是可以与广泛的呼叫签名和返回类型中的任何一种进行操作的方法。

    在源代码中,对签名多态方法的调用将编译,而不管请求的符号类型描述符如何。 像往常一样,Java编译器使用给定的符号类型描述符针对命名方法发出一个invokevirtual指令。 不寻常的部分是符号类型描述符是从实际的参数和返回类型派生而不是方法声明。

    当JVM处理包含签名多态调用的字节码时,它将成功链接任何此类调用,而不管其符号类型描述符如何。 (为了保持类型安全性,JVM将通过适当的动态类型检查来保护此类呼叫,如其他地方所述)。

    字节码生成器(包括编译器后端)需要为这些方法发出未转换的符号类型描述符。 确定符号链接的工具需要接受这些未转换的描述符,而不报告链接错误。

    方法手柄和Core Reflection API之间的互操作

    Lookup API中使用工厂方法,由Core Reflection API对象表示的任何类成员都可以转换为行为上等效的方法句柄。 例如,反射方法可以使用Lookup.unreflect转换为方法句柄。 所得到的方法句柄通常提供对基础类成员的更直接和有效的访问。

    作为特殊情况,当Core Reflection API用于查看invokeExact的签名多态方法invokeExact或纯invoke时,它们显示为普通非多态方法。 它们的反射外观,如Class.getDeclaredMethod所示 ,不受其在该API中的特殊状态的影响。 例如, Method.getModifiers将准确报告任何类似声明的方法所需的修改位,包括在这种情况下为nativevarargs位。

    与任何反映的方法一样,这些方法(反映时)可以通过java.lang.reflect.Method.invoke调用。 但是,这种反射调用不会导致方法句柄调用。 这样的一个调用,如果传递所需的参数(一个单一的,类型为Object[] ),将忽略该参数,并将抛出一个UnsupportedOperationException

    由于invokevirtual指令可以在任何符号类型描述符下本地调用方法句柄,所以这种反射视图与通过字节码的这些方法的正常呈现相冲突。 因此,当Class.getDeclaredMethod反映出来时,这两种原生方法可能只被视为占位符。

    为了获得特定类型描述符的调用者方法,请使用MethodHandles.exactInvokerMethodHandles.invoker 对于任何指定的类型描述符, Lookup.findVirtual API还能够返回一个方法句柄来调用invokeExact或者简单的invoke

    方法句柄和Java泛型之间的互操作

    可以使用Java通用类型声明的方法,构造函数或字段获取方法句柄。 与Core Reflection API一样,方法句柄的类型将由源级类型的擦除构成。 调用方法句柄时,其参数或返回值转换类型的类型可能是通用类型或类型实例。 如果发生这种情况,编译器将在构建invokevirtual指令的符号类型描述符时,通过其擦除来替换这些类型。

    方法句柄在Java参数化(通用)类型方面并不表示其类似函数的类型,因为类函数类型和参数化Java类型之间存在三个不匹配。

    • 方法类型涵盖所有可能的概率,从无参数到最多允许参数的maximum number 泛型不是可变的,所以不能代表这一点。
    • 方法类型可以指定原始类型的参数,哪些Java通用类型不能覆盖。
    • 方法手柄(组合器)的高阶函数通常在广泛的函数类型(包括多个特征的函数类型)中是通用的。 使用Java类型参数来表示这种通用性是不可能的。

    Arity limit

    JVM对任何类型的所有方法和构造函数都施加255个堆栈参数的绝对限制。 在某些情况下,这个限制可能会更具限制性:
    • A longdouble参数计数(用于特性限制)作为两个参数插槽。
    • 非静态方法为调用该方法的对象消耗额外的参数。
    • 构造函数为正在构造的对象消耗额外的参数。
    • 由于方法句柄invoke方法(或其他签名 - 多态方法)是非虚拟的,除了任何非虚拟接收方对象之外,它还为方法句柄本身消耗额外的参数。
    这些限制意味着无法创建某些方法句柄,仅因为堆栈参数的JVM限制。 例如,如果静态JVM方法完全接受255个参数,则无法为其创建方法句柄。 尝试使用不可能的方法类型创建方法句柄导致一个IllegalArgumentException 特别地,方法句柄的类型不能具有最大255的精确度。
    从以下版本开始:
    1.7
    另请参见:
    MethodTypeMethodHandles
    • 方法摘要

      所有方法  接口方法  具体的方法 
      Modifier and Type 方法 描述
      MethodHandle asCollector​(int collectArgPos, Class<?> arrayType, int arrayLength)
      创建一个 数组收集方法句柄,它接收从给定位置开始的给定数量的位置参数,并将它们收集到数组参数中。
      MethodHandle asCollector​(Class<?> arrayType, int arrayLength)
      使 数组收集方法句柄接受给定数量的尾随位置参数并将其收集到数组参数中。
      MethodHandle asFixedArity​()
      创建一个 固定的arity方法句柄,否则相当于当前的方法句柄。
      MethodHandle asSpreader​(int spreadArgPos, Class<?> arrayType, int arrayLength)
      创建一个 数组扩展方法句柄,它可以在给定的位置接受一个数组参数,并将其元素作为位置参数扩展代替数组。
      MethodHandle asSpreader​(Class<?> arrayType, int arrayLength)
      创建一个 数组扩展方法句柄,它接受一个尾随数组参数,并将其元素作为位置参数传播。
      MethodHandle asType​(MethodType newType)
      生成一个适配器方法句柄,该句柄将当前方法句柄的类型适配为新类型。
      MethodHandle asVarargsCollector​(Class<?> arrayType)
      创建一个 可变的arity适配器,它可以接受任意数量的尾随位置参数并将其收集到数组参数中。
      MethodHandle bindTo​(Object x)
      将值 x绑定到方法句柄的第一个参数,而不调用它。
      Object invoke​(Object... args)
      调用方法句柄,允许任何调用者类型描述符,以及可选地对参数和返回值执行转换。
      Object invokeExact​(Object... args)
      调用方法句柄,允许任何调用者类型描述符,但需要确切的类型匹配。
      Object invokeWithArguments​(Object... arguments)
      执行可变元数调用,传递的参数在给定列表的方法处理,就好像通过不精确 invoke从呼叫位点,其仅提到类型 Object ,且其元数是参数列表的长度。
      Object invokeWithArguments​(List<?> arguments)
      执行变量arity调用,将给定数组中的参数传递给方法句柄,好像通过来自调用站点的不精确的 invoke ,该 引用站点仅提及类型 Object ,其特征是参数数组的长度。
      boolean isVarargsCollector​()
      确定此方法是否支持 variable arity调用。
      String toString​()
      返回方法句柄的字符串表示形式,从字符串 "MethodHandle"开始,以方法句柄类型的字符串表示形式结束。
      MethodType type​()
      报告此方法句柄的类型。
      MethodHandle withVarargs​(boolean makeVarargs)
      如果布尔标志为真,则将此方法的句柄改为 variable arity ,否则为 fixed arity
    • 方法详细信息

      • type

        public MethodType type​()
        报告此方法句柄的类型。 通过invokeExact每次调用此方法句柄必须与此类型完全匹配。
        结果
        方法句柄类型
      • invokeExact

        public final Object invokeExact​(Object... args)
                                 throws Throwable
        调用方法句柄,允许任何调用者类型描述符,但需要确切的类型匹配。 invokeExact调用站点上的符号类型描述符必须与此方法句柄的type完全匹配。 参数或返回值不允许转换。

        当通过Core Reflection API观察此方法时,它将显示为单个本机方法,获取对象数组并返回一个对象。 如果通过java.lang.reflect.Method.invoke直接通过JNI或间接通过Lookup.unreflect直接调用此本机方法,则会抛出一个UnsupportedOperationException

        参数
        args - 使用varargs静态表示的签名 - 多态参数列表
        结果
        签名多态结果,静态表示使用 Object
        异常
        WrongMethodTypeException - 如果目标的类型与调用者的符号类型描述符不相同
        Throwable - 底层方法抛出的东西通过方法句柄调用传播不变
      • invoke

        public final Object invoke​(Object... args)
                            throws Throwable
        调用方法句柄,允许任何调用者类型描述符,以及可选地对参数和返回值执行转换。

        如果呼叫站点的符号类型描述符与此方法句柄的type完全匹配,则呼叫如invokeExact所示

        否则,通过调用asType首先调整该方法句柄以将该方法句柄调整为所需类型,然后在调整后的方法句柄上调用invokeExact进行调用。

        实际上没有保证asType电话。 如果JVM可以预测进行调用的结果,则可以直接对调用者的参数进行调整,并根据自己的确切类型调用目标方法句柄。

        调用站点invoke处的解析类型描述符必须是接收器asType方法的有效参数。 特别地,如果被调用者不是variable arity collector ,则调用者必须指定与被调用者的类型相同的参数。

        当通过Core Reflection API观察此方法时,它将显示为单个本机方法,获取对象数组并返回一个对象。 如果通过java.lang.reflect.Method.invoke直接通过JNI或间接通过Lookup.unreflect直接调用此本机方法,则会抛出一个UnsupportedOperationException

        参数
        args - 使用varargs静态表示的签名 - 多态参数列表
        结果
        签名多态结果,静态表示为 Object
        异常
        WrongMethodTypeException - 如果目标的类型无法调整到调用者的符号类型描述符
        ClassCastException - 如果目标的类型可以调整到调用者,但参考转换失败
        Throwable - 底层方法抛出的东西通过方法句柄调用传播不变
      • invokeWithArguments

        public Object invokeWithArguments​(Object... arguments)
                                   throws Throwable
        执行变量arity调用,将给定列表中的参数传递给方法句柄,好像通过来自调用站点的不精确的invoke ,其中仅提及类型为Object ,其特征是参数列表的长度。

        具体来说,执行如下,通过以下步骤进行,尽管如果JVM可以预测它们的效果,则不保证调用这些方法。

        • 确定参数数组的长度为N 对于null引用, N=0
        • 确定N参数的一般类型TN ,如TN=MethodType.genericMethodType(N)
        • 将原始目标方法手柄MH0为所需类型,如MH1 = MH0.asType(TN)
        • 将数组扩展为N独立参数A0, ...
        • 调用解压缩参数的类型调整方法句柄:MH1.invokeExact(A0,...)。
        • 取返回值作为Object参考。

        由于asType步骤的操作,必要时将应用以下参数转换:

        • 参考铸造
        • 拆箱
        • 拓宽原始转换

        如果调用返回的结果是原始的,则调用返回的结果为boxed,如果返回类型为void,则强制为null。

        此呼叫等同于以下代码:

        
         MethodHandle invoker = MethodHandles.spreadInvoker(this.type(), 0);
         Object result = invoker.invokeExact(this, arguments);
         

        与签名多态方法invokeExactinvokeinvokeWithArguments可以通过Core Reflection API和JNI正常访问。 因此,它可以用作本机或反射代码和方法句柄之间的桥梁。

        参数
        arguments - 传递给目标的参数
        结果
        目标返回的结果
        异常
        ClassCastException - 如果参数无法通过引用转换转换
        WrongMethodTypeException - 如果目标的类型无法调整为采用给定数量的 Object参数
        Throwable - 目标方法调用抛出的东西
        另请参见:
        MethodHandles.spreadInvoker(java.lang.invoke.MethodType, int)
      • invokeWithArguments

        public Object invokeWithArguments​(List<?> arguments)
                                   throws Throwable
        执行变量arity调用,将给定数组中的参数传递给方法句柄,好像通过来自调用站点的不精确的invoke ,其中仅提及类型为Object ,其特征是参数数组的长度。

        此方法也等效于以下代码:

        
           invokeWithArguments(arguments.toArray())
         
        参数
        arguments - 传递给目标的参数
        结果
        目标返回的结果
        异常
        NullPointerException - 如果 arguments是空引用
        ClassCastException - 如果参数无法通过引用转换转换
        WrongMethodTypeException - 如果目标的类型不能被调整为采用给定数量的 Object参数
        Throwable - 目标方法调用抛出的东西
      • asType

        public MethodHandle asType​(MethodType newType)
        生成一个适配器方法句柄,该句柄将当前方法句柄的类型适配为新类型。 生成的方法句柄保证报告一个等于所需新类型的类型。

        如果原始类型和新类型相同,则返回this

        新方法句柄被调用时,将执行以下步骤:

        • 转换传入参数列表以匹配原始方法句柄的参数列表。
        • 在转换的参数列表中调用原始方法句柄。
        • 将原始方法句柄返回的任何结果转换为新方法句柄的返回类型。

        这种方法提供了invokeExact与普通,不准确的invoke之间的关键行为差异。 当调用者的类型描述符与被调用者完全匹配时,两种方法执行相同的步骤,但是当类型不同时,普通的invoke也会调用asType (或一些内部等效的)来匹配调用者和被调用者的类型。

        如果当前方法是一个可变的arity方法,那么handle参数列表转换可能涉及将数个参数转换并收集到一个数组中,如described elsewhere 在所有其他情况下,所有转换都将成对应用,这意味着每个参数或返回值都将转换为一个参数或返回值(或不返回值)。 应用的转换通过查看旧方法和新方法句柄类型的相应组件类型进行定义。

        T0T1是相应的新旧参数类型,或旧的和新的返回类型。 具体来说,对于一些有效的索引i ,让T0 =newType.parameterType(i)T1 =this.type().parameterType(i) 否则,以另一种方式返回值,让T0 =this.type().returnType()T1 =newType.returnType() 如果类型相同,则新方法句柄将不会更改相应的参数或返回值(如果有)。 否则,如果可能,将应用以下转换之一:

        • 如果T0T1是引用,则应用到T1的转换。 (这些类型不需要以任何特定的方式相关联,这是因为null的动态值可以转换为任何引用类型。)
        • 如果T0T1是原语,则应用Java方法调用转换(JLS 5.3)(如果存在)。 (具体来说, T0必须通过扩展的原语转换转换为T1
        • 如果T0是原语, T1是引用,则如果存在Java转换(JLS 5.5),则应用它。 (具体来说,该值从T0到其包装类包装,然后根据需要加宽到T1)
        • 如果T0是引用, T1是原语,则在运行时将应用拆箱转换,可能之后是对基本值进行Java方法调用转换(JLS 5.3)。 (这些是原始的扩展转换。) T0必须是包装类或超类型。 (在T0是Object的情况下,这些是java.lang.reflect.Method.invoke允许的转换。)拆箱转换必须有成功的可能性,这意味着如果T0本身不是封装类,则必须至少存在一个包装类TWT0的子类型,其未装箱原始值可以扩大到T1
        • 如果返回类型T1被标记为void,则返回的值将被丢弃
        • 如果返回类型T0为空, T1为引用,则引入空值。
        • 如果返回类型T0为空, T1为原语,则引入零值。
        注意: T0T1都可以被视为静态类型,因为它们都不具体对应于任何实际参数或返回值的动态类型 。)

        如果无法进行任何一个所需的成对转换,则无法进行方法句柄转换。

        在运行时,应用于引用参数或返回值的转换可能需要额外的运行时检查,这可能会失败。 拆箱操作可能会失败,因为原始引用为null,导致NullPointerException 一个拆箱操作或一个引用转换也可能引用一个错误类型的对象,导致一个ClassCastException 虽然拆箱操作可能会接受几种包装,但是如果没有可用的话,那么ClassCastException将被抛出。

        参数
        newType - 新方法句柄的预期类型
        结果
        一个方法句柄,在执行任何必要的参数转换后委托给 this ,并安排任何必要的返回值转换
        异常
        NullPointerException - 如果 newType是空引用
        WrongMethodTypeException - 如果不能进行转换
        另请参见:
        MethodHandles.explicitCastArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)
      • asSpreader

        public MethodHandle asSpreader​(Class<?> arrayType,
                                       int arrayLength)
        创建一个数组扩展方法句柄,它接受一个尾随数组参数,并将其元素作为位置参数传播。 新的方法句柄适应当前方法句柄的目标 适配器的类型将与目标的类型相同,但目标类型的最终arrayLength参数被替换为arrayType型的单个数组参数。

        如果数组元素类型与原始目标上的任何相应参数类型不同,则原始目标适用于直接获取数组元素,就像通过调用asType一样

        调用时,适配器将数组元素的尾随数组参数替换为每个对象的自身参数。 (参数的顺序保留。)它们通过转换和/或取消装箱成对转换为目标的尾随参数的类型。 最后调用目标。 目标最终返回的内容不会被适配器返回。

        在调用目标之前,适配器会验证数组是否包含足够的元素,以便为目标方法句柄提供正确的参数计数。 200的X-454545新新新新新200新新200新新200新新200新新新200新新200新新200新新200新新200新新新200新新新200新新200新新新新新新评名新旗

        如果调用适配器时,提供的数组参数不具有正确数量的元素,则适配器将抛出一个IllegalArgumentException而不是调用该目标。

        以下是阵列扩展方法句柄的一些简单示例:

        
        MethodHandle equals = publicLookup()
          .findVirtual(String.class, "equals", methodType(boolean.class, Object.class));
        assert( (boolean) equals.invokeExact("me", (Object)"me"));
        assert(!(boolean) equals.invokeExact("me", (Object)"thee"));
        // spread both arguments from a 2-array:
        MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
        assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
        assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
        // try to spread from anything but a 2-array:
        for (int n = 0; n <= 10; n++) {
          Object[] badArityArgs = (n == 2 ? null : new Object[n]);
          try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }
          catch (IllegalArgumentException ex) { } // OK
        }
        // spread both arguments from a String array:
        MethodHandle eq2s = equals.asSpreader(String[].class, 2);
        assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
        assert(!(boolean) eq2s.invokeExact(new String[]{ "me", "thee" }));
        // spread second arguments from a 1-array:
        MethodHandle eq1 = equals.asSpreader(Object[].class, 1);
        assert( (boolean) eq1.invokeExact("me", new Object[]{ "me" }));
        assert(!(boolean) eq1.invokeExact("me", new Object[]{ "thee" }));
        // spread no arguments from a 0-array or null:
        MethodHandle eq0 = equals.asSpreader(Object[].class, 0);
        assert( (boolean) eq0.invokeExact("me", (Object)"me", new Object[0]));
        assert(!(boolean) eq0.invokeExact("me", (Object)"thee", (Object[])null));
        // asSpreader and asCollector are approximate inverses:
        for (int n = 0; n <= 2; n++) {
            for (Class<?> a : new Class<?>[]{Object[].class, String[].class, CharSequence[].class}) {
                MethodHandle equals2 = equals.asSpreader(a, n).asCollector(a, n);
                assert( (boolean) equals2.invokeWithArguments("me", "me"));
                assert(!(boolean) equals2.invokeWithArguments("me", "thee"));
            }
        }
        MethodHandle caToString = publicLookup()
          .findStatic(Arrays.class, "toString", methodType(String.class, char[].class));
        assertEquals("[A, B, C]", (String) caToString.invokeExact("ABC".toCharArray()));
        MethodHandle caString3 = caToString.asCollector(char[].class, 3);
        assertEquals("[A, B, C]", (String) caString3.invokeExact('A', 'B', 'C'));
        MethodHandle caToString2 = caString3.asSpreader(char[].class, 2);
        assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray()));
         
        参数
        arrayType - 通常是 Object[] ,从中提取扩展参数的数组参数的类型
        arrayLength - 从传入数组参数传播的参数数
        结果
        一个新的方法句柄,在调用原始方法句柄之前扩展其最后的数组参数
        异常
        NullPointerException - 如果 arrayType是空引用
        IllegalArgumentException - 如果 arrayType不是数组类型,或者如果目标不具有至少 arrayLength参数类型,或者如果 arrayLength为负,或者如果生成的方法句柄的类型将具有 too many parameters
        WrongMethodTypeException - 如果隐含的 asType调用失败
        另请参见:
        asCollector(java.lang.Class<?>, int)
      • asSpreader

        public MethodHandle asSpreader​(int spreadArgPos,
                                       Class<?> arrayType,
                                       int arrayLength)
        创建一个数组扩展方法句柄,它可以在给定的位置接受一个数组参数,并将其元素作为位置参数扩展代替数组。 新的方法句柄适应当前方法句柄的目标 适配器的类型将与目标的类型相同,不同之处在于从零spreadArgPos位置spreadArgPos开始的目标类型的arrayLength参数由spreadArgPos的单个数组参数arrayType

        该方法的行为非常像asSpreader(Class, int) ,但是接受一个额外的spreadArgPos参数来指示参数列表中哪个位置应该发生扩展。

        API Note:
        例:
        
            MethodHandle compare = LOOKUP.findStatic(Objects.class, "compare", methodType(int.class, Object.class, Object.class, Comparator.class));
            MethodHandle compare2FromArray = compare.asSpreader(0, Object[].class, 2);
            Object[] ints = new Object[]{3, 9, 7, 7};
            Comparator<Integer> cmp = (a, b) -> a - b;
            assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 0, 2), cmp) < 0);
            assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 1, 3), cmp) > 0);
            assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 2, 4), cmp) == 0);
         
        参数
        spreadArgPos - 扩展应该开始的参数列表中的位置(从零开始的索引)。
        arrayType - 通常是 Object[] ,从中提取扩展参数的数组参数的类型
        arrayLength - 从传入数组参数传播的参数数
        结果
        在调用原始方法句柄之前,将新的方法句柄扩展到给定位置的数组参数
        异常
        NullPointerException - 如果 arrayType是空引用
        IllegalArgumentException - 如果 arrayType不是数组类型,或者如果目标不具有至少 arrayLength参数类型,或者如果 arrayLength为负数,或者如果 spreadArgPos具有非法值(负数或与arrayLength超过参数数量一起),或如果结果方法句柄的类型将具有 too many parameters
        WrongMethodTypeException - 如果隐含的 asType调用失败
        从以下版本开始:
        9
        另请参见:
        asSpreader(Class, int)
      • withVarargs

        public MethodHandle withVarargs​(boolean makeVarargs)
        如果布尔标志为真,则将此方法的句柄改为variable arity ,否则为fixed arity 如果方法句柄已经是正确的arity模式,则返回不变。
        API Note:

        当适应可能是可变的方法句柄时,这种方法有时是有用的,以确保当且只有原始句柄时,生成的适配器也是可变的。 例如,该代码将句柄mh的第一个参数更改为int而不会影响其可变的arity属性: mh.asType(mh.type().changeParameterType(0,int.class)) .withVarargs(mh.isVarargsCollector())

        参数
        makeVarargs - 如果返回方法句柄应具有变量arity行为, makeVarargs true
        结果
        相同类型的方法句柄,具有可能调整的变量特征行为
        异常
        IllegalArgumentException - 如果 makeVarargs为真,并且此方法句柄没有尾数组参数
        从以下版本开始:
        9
        另请参见:
        asVarargsCollector(java.lang.Class<?>)asFixedArity()
      • asCollector

        public MethodHandle asCollector​(Class<?> arrayType,
                                        int arrayLength)
        使数组收集方法句柄接受给定数量的尾随位置参数并将其收集到数组参数中。 新的方法句柄适应当前方法句柄的目标 适配器的类型与目标的类型相同,不同之处在于单个尾随参数(通常为arrayType )由arrayLength类型的元素类型为arrayType参数替换。

        如果数组类型与原始目标的最终参数类型不同,则原始目标适合直接采用数组类型,就像通过调用asType一样

        当被调用时,该适配器替换其尾随arrayLength由类型的单个新数组参数arrayType ,其元素包括(按顺序)被替换的参数。 最后调用目标。 目标最终返回的内容不会被适配器返回。

        (当arrayLength为零时,数组也可能是共享常量。)

        注意: arrayType通常与原始目标的最后一个参数类型相同,是asSpreader对称性的明确参数,也允许目标使用简单的Object作为其最后一个参数类型。)

        为了创建不限于特定数量的收集参数的收集适配器,请改用asVarargsCollectorwithVarargs

        以下是数组收集方法句柄的一些示例:

        
        MethodHandle deepToString = publicLookup()
          .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
        assertEquals("[won]",   (String) deepToString.invokeExact(new Object[]{"won"}));
        MethodHandle ts1 = deepToString.asCollector(Object[].class, 1);
        assertEquals(methodType(String.class, Object.class), ts1.type());
        //assertEquals("[won]", (String) ts1.invokeExact(         new Object[]{"won"})); //FAIL
        assertEquals("[[won]]", (String) ts1.invokeExact((Object) new Object[]{"won"}));
        // arrayType can be a subtype of Object[]
        MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
        assertEquals(methodType(String.class, String.class, String.class), ts2.type());
        assertEquals("[two, too]", (String) ts2.invokeExact("two", "too"));
        MethodHandle ts0 = deepToString.asCollector(Object[].class, 0);
        assertEquals("[]", (String) ts0.invokeExact());
        // collectors can be nested, Lisp-style
        MethodHandle ts22 = deepToString.asCollector(Object[].class, 3).asCollector(String[].class, 2);
        assertEquals("[A, B, [C, D]]", ((String) ts22.invokeExact((Object)'A', (Object)"B", "C", "D")));
        // arrayType can be any primitive array type
        MethodHandle bytesToString = publicLookup()
          .findStatic(Arrays.class, "toString", methodType(String.class, byte[].class))
          .asCollector(byte[].class, 3);
        assertEquals("[1, 2, 3]", (String) bytesToString.invokeExact((byte)1, (byte)2, (byte)3));
        MethodHandle longsToString = publicLookup()
          .findStatic(Arrays.class, "toString", methodType(String.class, long[].class))
          .asCollector(long[].class, 1);
        assertEquals("[123]", (String) longsToString.invokeExact((long)123));
         

        注意:即使原始目标方法句柄是,生成的适配器从不是variable-arity method handle

        参数
        arrayType - 通常是 Object[] ,将会收集参数的数组参数的类型
        arrayLength - 要收集到新数组参数中的参数数
        结果
        一个新的方法句柄,在调用原始方法句柄之前,将一些尾随参数收集到数组中
        异常
        NullPointerException - 如果 arrayType是空引用
        IllegalArgumentException - 如果 arrayType不是数组类型,或者 arrayType不能分配给该方法句柄的尾随参数类型,或者 arrayLength不是合法的数组大小,或者结果方法句柄的类型将具有 too many parameters
        WrongMethodTypeException - 如果隐含的 asType调用失败
        另请参见:
        asSpreader(java.lang.Class<?>, int)asVarargsCollector(java.lang.Class<?>)
      • asCollector

        public MethodHandle asCollector​(int collectArgPos,
                                        Class<?> arrayType,
                                        int arrayLength)
        创建一个数组收集方法句柄,它接收从给定位置开始的给定数量的位置参数,并将它们收集到数组参数中。 新的方法句柄适应当前方法句柄的目标 适配器的类型与目标的类型相同,不同之处在于collectArgPos (通常为arrayType )所示位置的参数被arrayLength的元素类型为arrayType参数所取代。

        此方法的行为非常像asCollector(Class, int) ,但其不同之处在于其collectArgPos参数表示应在哪个位置参数列表参数中收集。 此索引为零。

        API Note:
        例子:
        
            StringWriter swr = new StringWriter();
            MethodHandle swWrite = LOOKUP.findVirtual(StringWriter.class, "write", methodType(void.class, char[].class, int.class, int.class)).bindTo(swr);
            MethodHandle swWrite4 = swWrite.asCollector(0, char[].class, 4);
            swWrite4.invoke('A', 'B', 'C', 'D', 1, 2);
            assertEquals("BC", swr.toString());
            swWrite4.invoke('P', 'Q', 'R', 'S', 0, 4);
            assertEquals("BCPQRS", swr.toString());
            swWrite4.invoke('W', 'X', 'Y', 'Z', 3, 1);
            assertEquals("BCPQRSZ", swr.toString());
         

        注意:即使原始的目标方法句柄是,生成的适配器从不是variable-arity method handle

        参数
        collectArgPos - 参数列表中从零开始收集的位置。
        arrayType - 通常是 Object[] ,将收集参数的数组参数的类型
        arrayLength - 要收集到新数组参数中的参数数
        结果
        在调用原始方法句柄之前,将一些参数收集到数组中的新方法句柄
        异常
        NullPointerException - 如果 arrayType是空引用
        IllegalArgumentException - 如果 arrayType不是数组类型,或 arrayType不能分配给该方法句柄的数组参数类型,或者 arrayLength不是合法的数组大小,或者 collectArgPos具有非法值(负数或大于参数数),或结果方法句柄的类型将具有 too many parameters
        WrongMethodTypeException - 如果隐含的 asType调用失败
        从以下版本开始:
        9
        另请参见:
        asCollector(Class, int)
      • asVarargsCollector

        public MethodHandle asVarargsCollector​(Class<?> arrayType)
        创建一个可变的arity适配器,它可以接受任意数量的尾随位置参数并将其收集到数组参数中。

        适配器的类型和行为将与目标的类型和行为相同,但某些invokeasType请求可能会导致尾随的位置参数被收集到目标的尾随参数中。 此外,适配器的最后一个参数类型将为arrayType ,即使目标具有不同的最后一个参数类型。

        这种转化可以返回this ,如果该方法是手柄元数可变的已和它的尾部参数类型是相同的arrayType

        当用invokeExact调用时,适配器调用目标,而不改变参数。 注意:此行为与fixed arity collector不同,因为它接受一个不确定长度的整个数组,而不是固定数量的参数)。

        当使用普通的,不准确的invoke调用时,如果调用者类型与适配器相同,则适配器会像invokeExact一样调用目标。 (这是类型匹配时invoke的正常行为。)

        否则,如果调用者和适配器类型相同,并且调用者的尾部参数类型是与适配器的尾部参数类型相同或可分配的引用类型,则参数和返回值将成对转换,如同通过asType在固定的方法手柄上。

        否则,电平不一致,或适配器的尾随参数类型不能从相应的呼叫者类型分配。 在这种情况下,适配器将从原始的尾随参数位置arrayType新的arrayTypearrayType ,其元素包括(按顺序)替换的参数。

        调用者类型必须提供足够的参数和正确类型,以满足目标对尾随数组参数之前位置参数的要求。 因此,呼叫者必须至少提供N-1参数,其中N是目标的真实性。 此外,必须存在从传入参数到目标参数的转换。 与普通invoke其他用途invoke ,如果这些基本要求不能满足,可能会抛出一个WrongMethodTypeException

        在所有情况下,最终返回的目标将由适配器保持不变。

        在最后的情况下,正好像目标方法句柄暂时适应了呼叫者类型所要求的一个fixed arity collector (与asCollector ,如果数组长度为零,则可以使用共享常量而不是新数组,如果对asCollector的隐含调用将抛出一个IllegalArgumentExceptionWrongMethodTypeException ,则对变量arity适配器的调用必须抛出WrongMethodTypeException ))

        asType的行为也是专门针对可变局域适配器,维持不变量,平坦,不精确的invoke总是相当于一个asType调用调整目标类型,其次是invokeExact 因此,当且仅当适配器和请求的类型在正态分布或尾随参数类型不同时,可变地区适配器才能响应asType请求。 所得到的固定收集器的类型通过成对转换进一步调整(如果需要)到所请求的类型,好像另外应用了asType

        当通过执行CONSTANT_MethodHandle常量的ldc指令获取方法句柄,并将目标方法标记为可变方法(具有修饰符位0x0080 )时,方法句柄将接受多个特征,就好像方法句柄常数为通过调用asVarargsCollector

        为了创建收集预定数量的参数并且其类型反映该预定数量的收集适配器,代之以使用asCollector

        没有方法句柄转换可以产生具有可变原型的新方法句柄,除非它们被记录为这样做。 因此,除了asVarargsCollectorwithVarargs ,在所有方法MethodHandleMethodHandles将返回一个方法手柄固定元数,除非他们被指定为返回原来的操作数(例如,案件asType的方法处理自己的类型)。

        调用asVarargsCollector的方法句柄已经是可变的,将产生一个具有相同类型和行为的方法句柄。 它可能(或可能不)返回原始变量arity方法句柄。

        这是一个例子,一个列表制作变量arity方法句柄:

        
        MethodHandle deepToString = publicLookup()
          .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
        MethodHandle ts1 = deepToString.asVarargsCollector(Object[].class);
        assertEquals("[won]",   (String) ts1.invokeExact(    new Object[]{"won"}));
        assertEquals("[won]",   (String) ts1.invoke(         new Object[]{"won"}));
        assertEquals("[won]",   (String) ts1.invoke(                      "won" ));
        assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"}));
        // findStatic of Arrays.asList(...) produces a variable arity method handle:
        MethodHandle asList = publicLookup()
          .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
        assertEquals(methodType(List.class, Object[].class), asList.type());
        assert(asList.isVarargsCollector());
        assertEquals("[]", asList.invoke().toString());
        assertEquals("[1]", asList.invoke(1).toString());
        assertEquals("[two, too]", asList.invoke("two", "too").toString());
        String[] argv = { "three", "thee", "tee" };
        assertEquals("[three, thee, tee]", asList.invoke(argv).toString());
        assertEquals("[three, thee, tee]", asList.invoke((Object[])argv).toString());
        List ls = (List) asList.invoke((Object)argv);
        assertEquals(1, ls.size());
        assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
         

        讨论:这些规则被设计为可变方法的Java规则的动态类型变体。 在这两种情况下,调用变量arity方法或方法句柄都可以传递零个或多个位置参数,否则可以传递任何长度的预先收集的数组。 用户应该意识到最终参数的特殊角色,以及类型匹配对最终参数的影响,该参数决定了单个尾随参数是否被解释为数组的整个数组或单个元素。集。 请注意,尾随参数的动态类型对此决定没有影响,只是调用站点的符号类型描述符和方法句柄的类型描述符之间的比较。)

        参数
        arrayType - 通常是 Object[] ,将收集参数的数组参数的类型
        结果
        一个新的方法句柄,可以在调用原始方法句柄之前收集任意数量的尾随参数到数组中
        异常
        NullPointerException - 如果 arrayType是空引用
        IllegalArgumentException - 如果 arrayType不是数组类型或 arrayType不能分配给该方法句柄的尾随参数类型
        另请参见:
        asCollector(java.lang.Class<?>, int)isVarargsCollector()withVarargs(boolean)asFixedArity()
      • isVarargsCollector

        public boolean isVarargsCollector​()
        确定此方法是否支持variable arity调用。 这种方法处理来自以下来源:
        • 致电asVarargsCollector
        • 调用一个lookup method ,它解析为一个可变的arity Java方法或构造函数
        • 一个ldc一个的指令CONSTANT_MethodHandle其解析为一个可变参数数量的Java方法或构造
        结果
        如果这个方法句柄接受多于一个的纯粹的,不准确的 invoke调用, invoke
        另请参见:
        asVarargsCollector(java.lang.Class<?>)asFixedArity()
      • asFixedArity

        public MethodHandle asFixedArity​()
        创建一个固定的arity方法句柄,否则相当于当前的方法句柄。

        如果当前方法句柄不是variable arity ,则返回当前的方法句柄。 即使当前的方法句柄不能是有效的输入到asVarargsCollector

        否则,所得到的固定方法句柄具有与当前方法句柄相同的类型和行为,但isVarargsCollector将为false。 固定方法句柄可以(或可能不是)是asVarargsCollector的先前参数。

        这是一个例子,一个列表制作变量arity方法句柄:

        
        MethodHandle asListVar = publicLookup()
          .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
          .asVarargsCollector(Object[].class);
        MethodHandle asListFix = asListVar.asFixedArity();
        assertEquals("[1]", asListVar.invoke(1).toString());
        Exception caught = null;
        try { asListFix.invoke((Object)1); }
        catch (Exception ex) { caught = ex; }
        assert(caught instanceof ClassCastException);
        assertEquals("[two, too]", asListVar.invoke("two", "too").toString());
        try { asListFix.invoke("two", "too"); }
        catch (Exception ex) { caught = ex; }
        assert(caught instanceof WrongMethodTypeException);
        Object[] argv = { "three", "thee", "tee" };
        assertEquals("[three, thee, tee]", asListVar.invoke(argv).toString());
        assertEquals("[three, thee, tee]", asListFix.invoke(argv).toString());
        assertEquals(1, ((List) asListVar.invoke((Object)argv)).size());
        assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
         
        结果
        一个只接受固定数量参数的新方法句柄
        另请参见:
        asVarargsCollector(java.lang.Class<?>)isVarargsCollector()withVarargs(boolean)
      • bindTo

        public MethodHandle bindTo​(Object x)
        将值x绑定到方法句柄的第一个参数,而不调用它。 新的方法句柄通过将其绑定到给定的参数来适配当前方法句柄作为其目标 绑定句柄的类型将与目标的类型相同,不同之处在于单个引用参考参数将被省略。

        当被调用时,绑定的句柄将给定值x作为新的引导参数插入目标。 其他论点也不变。 目标最终返回的结果由绑定句柄返回。

        参考x必须可转换为目标的第一个参数类型。

        注意:由于方法句柄是不可变的,所以目标方法句柄保留其原始类型和行为。

        注意:即使原始目标方法句柄是,生成的适配器从不是一个variable-arity method handle

        参数
        x - 绑定到目标的第一个参数的值
        结果
        一个新的方法句柄,在调用原始方法句柄之前,将给定值添加到传入参数列表
        异常
        IllegalArgumentException - 如果目标不具有引用类型的引导参数类型
        ClassCastException - 如果 x无法转换为目标的引导参数类型
        另请参见:
        MethodHandles.insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...)
      • toString

        public String toString​()
        返回方法句柄的字符串表示形式,从字符串"MethodHandle"开始,以方法句柄类型的字符串表示结束。 换句话说,这个方法返回一个等于下列值的字符串:
        
         "MethodHandle" + type().toString()
         

        注意:此API的未来版本可能会向字符串表示形式添加更多信息,因此,本语法不应由应用程序解析。)

        重写:
        toStringObject
        结果
        方法句柄的字符串表示法