Module java.base
Package java.lang.invoke

Class StringConcatFactory

java.lang.Object
java.lang.invoke.StringConcatFactory

public final class StringConcatFactory extends Object

用于简化创建字符串连接方法的方法,可以用于有效地连接已知数量的已知类型参数,可能在类型适应和部分参数评估之后使用。这些方法通常用作bootstrap方法,用于支持Java编程语言的 invokedynamic调用站点的字符串连接功能。

通过提供的MethodHandle间接访问指定的行为分为两个阶段:

  1. 链接发生在调用此类中的方法时。它们将作为参数接受描述连接参数计数和类型以及可选的字符串配方的方法类型,以及参与字符串连接的常量。有关接受的配方形状的详细信息将在下面进一步描述。链接可能涉及动态加载实现预期连接行为的新类。CallSite保存指向确切连接方法的MethodHandle。连接方法可以在不同的CallSite之间共享,例如,如果链接方法将它们作为纯函数生成。
  2. 调用发生在调用生成的连接方法时,使用确切的动态参数。对于单个连接方法,这可能发生多次。通过行为MethodHandle引用的方法将使用静态参数和在调用时提供的任何额外动态参数进行调用,就像通过MethodHandle.invoke(Object...)一样。

此类提供两种形式的链接方法:简单版本(makeConcat(java.lang.invoke.MethodHandles.Lookup, String, MethodType)),仅使用动态参数,以及高级版本(makeConcatWithConstants(java.lang.invoke.MethodHandles.Lookup, String, MethodType, String, Object...)),使用捕获常量参数的高级形式。高级策略可以生成边缘更好的调用字节码,但会增加运行时存在的字符串连接方法的形状数量,因为这些形状将包括常量静态参数。

API 注意:

有一个JVM限制(类文件结构约束):没有方法可以使用超过255个插槽进行调用。这限制了可以传递给引导方法的静态和动态参数的数量。由于存在使用MethodHandle组合器的潜在连接策略,我们需要在参数列表上保留一些空插槽来捕获临时结果。这就是为什么此工厂中的引导方法不接受超过200个参数插槽的原因。需要在连接中使用超过200个参数插槽的用户应该将大连接拆分为较小的表达式。

自 JDK 版本:
9
  • Field Details

    • MAX_INDY_CONCAT_ARG_SLOTS

      public static final int MAX_INDY_CONCAT_ARG_SLOTS
      MAX_INDY_CONCAT_ARG_SLOTS是Java平台的预览API。
      仅当启用预览功能时,程序才能使用MAX_INDY_CONCAT_ARG_SLOTS
      预览功能可能会在将来的版本中删除,或升级为Java平台的永久功能。
      字符串连接调用中的最大参数插槽数。虽然indy调用可以处理的最大参数插槽数为253,但我们并未使用所有这些插槽,以便让使用MethodHandle组合器的策略使用一些参数。
      自 JDK 版本:
      21
  • Method Details

    • makeConcat

      public static CallSite makeConcat(MethodHandles.Lookup lookup, String name, MethodType concatType) throws StringConcatException
      简化创建优化的字符串连接方法,可用于有效地连接已知数量的已知类型参数,可能在类型适应和部分参数评估之后使用。通常用作Java编程语言的字符串连接功能的 invokedynamic调用站点的bootstrap方法

      当从此方法返回的CallSite的目标被调用时,它返回字符串连接的结果,将传递给连接方法的所有函数参数作为连接的输入。目标签名由concatType给出。对于接受:

      • 零个输入,连接结果为空字符串;
      • 一个输入,连接结果为根据JLS 5.1.11“字符串转换”转换的单个输入;否则
      • 两个或更多输入,根据JLS 15.18.1“字符串连接运算符+”中规定的要求连接输入。输入将根据JLS 5.1.11“字符串转换”进行转换,并从左到右组合。

      假设连接参数如下:

      • concatType,描述CallSite签名

      那么以下连接不变量必须保持:

      • concatType中的参数插槽数小于或等于200
      • concatType中的返回类型可从String分配
      参数:
      lookup - 表示具有调用者访问权限的查找上下文。具体来说,查找上下文必须具有完全特权访问。在与invokedynamic一起使用时,VM会自动堆叠这个。
      name - 要实现的方法的名称。此名称是任意的,对于此链接方法没有意义。在与invokedynamic一起使用时,这由InvokeDynamic结构的NameAndType提供,并由VM自动堆叠。
      concatType - CallSite的预期签名。参数类型表示连接参数的类型;返回类型始终可从String分配。在与invokedynamic一起使用时,这由InvokeDynamic结构的NameAndType提供,并由VM自动堆叠。
      返回:
      一个CallSite,其目标可用于执行字符串连接,动态连接参数由给定的concatType描述。
      抛出:
      StringConcatException - 如果违反了此处描述的任何连接不变量,或查找上下文没有私有访问权限。
      NullPointerException - 如果任何传入参数为null。当使用invokedynamic调用引导方法时,这永远不会发生。
      参见Java语言规范
      5.1.11 字符串转换
      15.18.1 字符串连接运算符 +
    • makeConcatWithConstants

      public static CallSite makeConcatWithConstants(MethodHandles.Lookup lookup, String name, MethodType concatType, String recipe, Object... constants) throws StringConcatException
      便于创建优化的字符串连接方法,可用于有效地连接已知数量和已知类型的参数,可能在类型适应和部分参数评估之后。通常用作引导方法,用于支持Java编程语言的字符串连接功能。

      当从此方法返回的CallSite的目标被调用时,它返回字符串连接的结果,将所有函数参数和常量作为连接方法调用时的输入进行连接。目标签名由concatType给出,并不包括常量。对于接受以下内容的目标:

      • 零个输入,连接导致空字符串;
      • 一个输入,连接导致单个输入按照JLS 5.1.11 "字符串转换"转换;否则
      • 两个或更多输入,根据JLS 15.18.1 "字符串连接运算符+"中规定的要求连接输入。输入按照JLS 5.1.11 "字符串转换"进行转换,并从左到右组合。

      连接配方是从参数和常量构造连接字符串的方式的字符串描述。配方从左到右处理,每个字符代表连接的一个输入。配方字符含义如下:

      • \1 (Unicode点0001):普通参数。此输入通过动态参数传递,并在连接方法调用期间提供。此输入可以为null。
      • \2 (Unicode点0002):常量。此输入通过静态引导参数传递。此常量可以是常量池中可表示的任何值。如果需要,工厂将调用toString执行一次字符串转换。
      • 任何其他字符值:单个字符常量。

      假设链接参数如下:

      • concatType,描述CallSite签名
      • recipe,描述字符串配方
      • constants,常量的可变参数数组

      那么以下链接不变性必须保持:

      • concatType中的参数槽数小于或等于200
      • concatType中的参数计数等于recipe中\1标记的数量
      • concatType中的返回类型可赋值给String,并且与返回的MethodHandle的返回类型匹配
      • constants中的元素数等于recipe中\2标记的数量
      API注释:
      代码生成器有三种不同的方式来处理字符串连接表达式中的常量字符串操作数S。首先,S可以被实例化为引用(使用ldc)并作为普通参数传递(配方'\1')。或者,S可以存储在常量池中并作为常量传递(配方'\2')。最后,如果S既不包含配方标记字符('\1','\2'),则S可以插入到配方本身中,导致其字符被插入到结果中。
      参数:
      lookup - 表示具有调用者访问权限的查找上下文。具体来说,查找上下文必须具有完全特权访问。在与invokedynamic一起使用时,VM会自动堆叠这个。
      name - 要实现的方法的名称。此名称是任意的,对于此链接方法没有意义。在与invokedynamic一起使用时,这是由InvokeDynamic结构的NameAndType提供的,并由VM自动堆叠。
      concatType - CallSite的预期签名。参数类型表示动态连接参数的类型;返回类型始终可赋值给String。在与invokedynamic一起使用时,这是由InvokeDynamic结构的NameAndType提供的,并由VM自动堆叠。
      recipe - 描述的连接配方。
      constants - 代表传递给链接方法的常量的可变参数。
      返回:
      一个CallSite,其目标可用于执行字符串连接,动态连接参数由给定的concatType描述。
      抛出:
      StringConcatException - 如果违反了这里描述的任何链接不变性,或查找上下文没有私有访问权限。
      NullPointerException - 如果任何传入参数为null,或recipe中的任何常量为null。当使用invokedynamic调用引导方法时,这永远不会发生。
      参见Java语言规范
      5.1.11 字符串转换
      15.18.1 字符串连接运算符 +
    • makeConcatWithTemplate

      public static MethodHandle makeConcatWithTemplate(List<String> fragments, List<Class<?>> ptypes) throws StringConcatException
      makeConcatWithTemplate是Java平台的预览API。
      仅当启用预览功能时,程序才能使用makeConcatWithTemplate
      预览功能可能会在将来的版本中删除,或升级为Java平台的永久功能。
      简化的连接方法,用于简化StringTemplate预览连接。此方法返回一个单个连接方法,交错片段和值。片段|值|片段|值|...|值|片段。片段数量必须比ptypes的数量多一个。ptypes使用的总槽数必须小于或等于MAX_INDY_CONCAT_ARG_SLOTS预览
      参数:
      fragments - 字符串片段列表
      ptypes - 表达式类型列表
      返回:
      用于连接的MethodHandle
      抛出:
      StringConcatException - 如果违反了任何链接不变性。
      NullPointerException - 如果任何传入参数为null。
      IllegalArgumentException - 如果值槽的数量超过MAX_INDY_CONCAT_ARG_SLOTS预览
      自:
      21
    • makeConcatWithTemplateCluster

      public static List<MethodHandle> makeConcatWithTemplateCluster(List<String> fragments, List<Class<?>> ptypes, int maxSlots) throws StringConcatException
      makeConcatWithTemplateCluster是Java平台的预览API。
      仅当启用预览功能时,程序才能使用makeConcatWithTemplateCluster
      预览功能可能会在将来的版本中删除,或升级为Java平台的永久功能。
      此方法将大型连接分解为基于每个MethodHandle所需槽的数量的单独MethodHandles。第一个之后的每个MethodHandle将具有前一个MethodHandle的结果的额外String槽。使用makeConcatWithTemplate(java.util.List<java.lang.String>, java.util.List<java.lang.Class<?>>)预览来构造MethodHandles。ptypes使用的总槽数是开放式的。但是,在组合MethodHandles时必须小心,以确保组合总数不超过255槽限制。
      参数:
      fragments - 字符串片段列表
      ptypes - 表达式类型列表
      maxSlots - 每个MethodHandle的最大槽数。
      返回:
      MethodHandles列表
      抛出:
      IllegalArgumentException - 如果maxSlots不在1和MAX_INDY_CONCAT_ARG_SLOTS之间。
      StringConcatException - 如果违反了任何链接不变性。
      NullPointerException - 如果任何传入参数为null。
      IllegalArgumentException - 如果值槽的数量超过MAX_INDY_CONCAT_ARG_SLOTS预览
      自:
      21
    • makeConcatWithTemplateGetters

      public static MethodHandle makeConcatWithTemplateGetters(List<String> fragments, List<MethodHandle> getters, int maxSlots) throws StringConcatException
      makeConcatWithTemplateGetters是Java平台的预览API。
      仅当启用预览功能时,程序才能使用makeConcatWithTemplateGetters
      预览功能可能会在将来的版本中被移除,或升级为Java平台的永久功能。
      该方法创建一个期望一个输入的MethodHandle,即提供的getter的接收者。该方法使用makeConcatWithTemplateCluster(java.util.List<java.lang.String>, java.util.List<java.lang.Class<?>>, int)预览来创建中间的MethodHandles
      参数:
      fragments - 字符串片段列表
      getters - getter MethodHandles 列表
      maxSlots - 每个集群中MethodHandle的最大槽位数。
      返回:
      连接的MethodHandle
      抛出:
      IllegalArgumentException - 如果maxSlots不在1和MAX_INDY_CONCAT_ARG_SLOTS之间,或者getter不使用相同的参数类型
      StringConcatException - 如果违反任何链接不变量
      NullPointerException - 如果任何传入参数为null
      IllegalArgumentException - 如果值槽位数超过MAX_INDY_CONCAT_ARG_SLOTS预览
      自:
      21