模块 java.base

类 MethodHandles.Lookup

java.lang.Object
java.lang.invoke.MethodHandles.Lookup
封闭类:
MethodHandles

public static final class MethodHandles.Lookup extends Object
lookup object 是创建方法句柄的工厂,当创建需要访问检查时。方法句柄在调用时不执行访问检查,而是在创建时执行。因此,在创建方法句柄时必须强制执行方法句柄访问限制。执行这些限制的调用者类称为 查找类

需要创建方法句柄的查找类将调用 MethodHandles.lookup 为自己创建一个工厂。创建 Lookup 工厂对象时,确定查找类的标识,并将其安全地存储在 Lookup 对象中。查找类(或其委托)然后可以使用 Lookup 对象上的工厂方法来为访问检查成员创建方法句柄。这包括查找类允许的所有方法、构造函数和字段,甚至是私有的。

查找工厂方法

Lookup 对象上的工厂方法对应于方法、构造函数和字段的所有主要用例。工厂方法创建的每个方法句柄都是特定 bytecode behavior 的功能等价物。 (字节码行为在 Java 虚拟机规范的 5.4.3.5 部分进行了描述。)以下是这些工厂方法与生成的方法句柄的行为之间的对应关系的摘要:
查找方法行为
查找表达式 成员 字节码行为
lookup.findGetter(C.class,"f",FT.class) FT f; (T) this.f;
lookup.findStaticGetter(C.class,"f",FT.class) static
FT f;
(FT) C.f;
lookup.findSetter(C.class,"f",FT.class) FT f; this.f = x;
lookup.findStaticSetter(C.class,"f",FT.class) static
FT f;
C.f = arg;
lookup.findVirtual(C.class,"m",MT) T m(A*); (T) this.m(arg*);
lookup.findStatic(C.class,"m",MT) static
T m(A*);
(T) C.m(arg*);
lookup.findSpecial(C.class,"m",MT,this.class) T m(A*); (T) super.m(arg*);
lookup.findConstructor(C.class,MT) C(A*); new C(arg*);
lookup.unreflectGetter(aField) static)?
FT f;
(FT) aField.get(thisOrNull);
lookup.unreflectSetter(aField) static)?
FT f;
aField.set(thisOrNull, arg);
lookup.unreflect(aMethod) static)?
T m(A*);
(T) aMethod.invoke(thisOrNull, arg*);
lookup.unreflectConstructor(aConstructor) C(A*); (C) aConstructor.newInstance(arg*);
lookup.unreflectSpecial(aMethod,this.class) T m(A*); (T) super.m(arg*);
lookup.findClass("C") class C { ... } C.class;
此处,类型 C 是正在搜索成员的类或接口,在查找方法中记录为名为 refc 的参数。方法类型 MT 由返回类型 T 和参数类型序列 A* 组成。构造函数还具有一系列参数类型 A* 并被视为返回类型为 C 的新创建对象。 MT 和字段类型 FT 都记录为名为 type 的参数。形参this代表C类型的自引用;如果存在,它始终是方法句柄调用的前导参数。 (在某些 protected 成员的情况下,this 的类型可能仅限于查找类;见下文。)名称 arg 代表所有其他方法句柄参数。在 Core Reflection API 的代码示例中,如果访问的方法或字段是静态的,则名称 thisOrNull 代表空引用,否则代表 this。名称 aMethodaFieldaConstructor 代表对应于类型 C 中声明的给定成员的反射对象。

findClass 操作的字节码行为是常量类的加载,就像 ldc CONSTANT_Class 一样。该行为不是表示为方法句柄,而是直接表示为 Class 常量。

在给定成员具有可变元数(即方法或构造函数)的情况下,返回的方法句柄也将为 变数 。在所有其他情况下,返回的方法句柄将具有固定的数量。

Discussion:查找的方法句柄和底层类成员以及字节码行为之间的等价性可以通过几种方式分解:

  • 如果 C 不能从查找类的加载器中以符号方式访问,查找仍然可以成功,即使没有等效的 Java 表达式或字节码常量。
  • 同样,如果 TMT 不能从查找类的加载器中以符号方式访问,查找仍然可以成功。例如,查找 MethodHandle.invokeExactMethodHandle.invoke 将始终成功,无论请求的类型如何。
  • 如果安装了安全管理器,它可以基于各种理由禁止查找 (见下文)。相比之下,CONSTANT_MethodHandle 常量上的 ldc 指令不受安全管理器检查。
  • 如果查找的方法具有 非常大的数量 ,则方法句柄创建可能会失败并显示 IllegalArgumentException ,因为方法句柄类型具有 参数太多。

访问检查

创建方法句柄时,访问检查应用于 Lookup 的工厂方法。这是与 Core Reflection API 的一个关键区别,因为 java.lang.reflect.Method.invoke 在每次调用时对每个调用者执行访问检查。

所有访问检查都从 Lookup 对象开始,该对象将其记录的查找类与创建方法句柄的所有请求进行比较。单个 Lookup 对象可用于创建任意数量的访问检查方法句柄,所有这些都针对单个查找类进行检查。

Lookup 对象可以与其他可信代码共享,例如元对象协议。共享的 Lookup 对象委托了在查找类的私有成员上创建方法句柄的能力。即使特权代码使用 Lookup 对象,访问检查也仅限于原始查找类的特权。

查找可能会失败,因为查找类无法访问包含类,或者因为缺少所需的类成员,或者因为查找类无法访问所需的类成员,或者因为查找对象不够可信访问该成员。对于 final 字段上的字段设置函数,最终执行被视为一种访问控制,查找将失败,但 Lookup.unreflectSetter 的特殊情况除外。在任何这些情况下,都会从尝试的查找中抛出 ReflectiveOperationException。确切的类将是以下之一:

  • NoSuchMethodException — 如果请求的方法不存在
  • NoSuchFieldException — 如果一个字段被请求但不存在
  • IllegalAccessException — 如果成员存在但访问检查失败

通常,可以为方法 M 查找方法句柄的条件并不比查找类可以编译、验证和解析对 M 的调用的条件更具限制性。在 JVM 会引发类似 NoSuchMethodError 的异常的地方,方法句柄查找通常会引发相应的已检查异常,例如 NoSuchMethodException 。调用查找产生的方法句柄的效果是 完全等同 执行对 M 的编译、验证和解析调用。字段和构造函数也是如此。

Discussion: 访问检查仅适用于命名和反射方法、构造函数和字段。其他方法句柄创建方法(例如 MethodHandle.asType )不需要任何访问检查,并且独立于任何 Lookup 对象使用。

如果所需成员是 protected ,则适用通常的 JVM 规则,包括查找类必须与所需成员位于同一包中或必须继承该成员的要求。 (参见 Java 虚拟机规范,4.9.25.4.3.56.4 部分。)此外,如果所需成员是不同包中的非静态字段或方法,则生成的方法句柄可能仅应用于查找的对象类或其子类之一。通过将前导 this 参数的类型从 C(必须是查找类的超类)缩小到查找类本身来强制执行此要求。

JVM 对 invokespecial 指令施加了类似的要求,即接收者参数必须与解析的方法 and 当前类匹配。同样,通过将前导参数的类型缩小为生成的方法句柄来强制执行此要求。 (请参阅 Java 虚拟机规范,4.10.1.9 部分。)

JVM 将构造函数和静态初始化程序块表示为具有特殊名称("<init>""<clinit>")的内部方法。调用指令的内部语法允许它们引用此类内部方法,就好像它们是普通方法一样,但 JVM 字节码验证器拒绝它们。查找此类内部方法将生成 NoSuchMethodException

如果嵌套类型之间的关系直接通过 NestHostNestMembers 属性表示(参见 Java 虚拟机规范,4.7.284.7.29 部分),则关联的 Lookup 对象提供对查找类及其所有 nestmates 的直接访问(参见 Class.getNestHost ) .否则,嵌套类之间的访问由 Java 编译器创建包装器方法来访问同一嵌套中另一个类的私有方法。例如,嵌套类 C.D 可以访问其他相关类(如 CC.D.EC.B )中的私有成员,但 Java 编译器可能需要在这些相关类中生成包装方法。在这种情况下,C.E 上的 Lookup 对象将无法访问这些私有成员。此限制的解决方法是 Lookup.in 方法,它可以将对 C.E 的查找转换为对任何其他类的查找,而无需特殊的特权提升。

根据其 lookupModes 的集合,允许对给定查找对象的访问可能仅限于查找类通常可访问的成员子集。例如,publicLookup 方法生成一个查找对象,该对象只允许访问导出包的公共类中的公共成员。调用者敏感方法 lookup 生成一个具有与其调用者类相关的全部功能的查找对象,以模拟所有支持的字节码行为。此外,Lookup.in 方法可能会生成比原始查找对象访问模式更少的查找对象。

Discussion of private and module access: 我们说查找有 private access 如果它的 查找模式 包括访问 private 成员(包括 nestmates 的私有成员)的可能性。正如其他地方的相关方法中所记录的那样,只有具有私有访问权限的查找才具有以下功能:

同样,具有模块访问权限的查找可确保原始查找创建者是与查找类相同的模块中的成员。

私有和模块访问是独立确定的模式;查找可能有一个或两个或两个都没有。拥有两种访问模式的查找被称为拥有 完全权限访问

使用 original access 进行查找可确保此查找是由原始查找类和 VM 调用的引导方法创建的。这种具有原始访问权限的查找也具有私有和模块访问权限,具有以下附加功能:

  • 创建调用 来电敏感 方法的方法句柄,例如 Class.forName
  • 获取与查找类关联的类数据

这些权限中的每一个都是以下事实的结果:具有私有访问权限的查找对象可以安全地追溯到原始类,其 字节码行为 和 Java 语言访问权限可以通过方法句柄可靠地确定和模拟。

跨模块查找

当一个模块 M1 中的查找类访问另一个模块 M2 中的类时,会在访问模式位之外执行额外的访问检查。当 M2M1 可读且类型位于 M2 的包中且至少导出到 M1 时,具有 PUBLIC 模式和 M1 中的查找类的 Lookup 可以访问 M2 中的公共类型。

C 上的 Lookup 也可以通过 Lookup.in MethodHandles.privateLookupIn 方法 teleport 到目标类。跨模块传送将始终将原始查找类记录为 previous lookup class 并丢弃 MODULE 访问权限。如果目标类与查找类 C 在同一个模块中,则目标类成为新的查找类,并且与之前的查找类没有变化。如果目标类与 M1C 的模块)位于不同的模块中,则 C 成为新的先前查找类,目标类成为新的查找类。在这种情况下,如果 M0 中已经有一个先前的查找类,并且它不同于 M1M2 ,那么生成的查找将放弃所有特权。例如,

Lookup lookup = MethodHandles.lookup();  // in class C
Lookup lookup2 = lookup.in(D.class);
MethodHandle mh = lookup2.findStatic(E.class, "m", MT);
 

MethodHandles.lookup() 工厂方法生成一个带有 null 先前查找类的 Lookup 对象。 lookup.in(D.class) 将类 C 上的 lookup 转换为类 D 而无需提升权限。如果 CD 在同一个模块中,lookup2D 记录为新的查找类,并保留与原始 lookupnull(如果不存在)相同的先前查找类。

Lookup 从一个巢穴中的一个类传送到另一个巢穴时,PRIVATE 访问权限将被删除。当 Lookup 从一个包中的类传送到另一个包时,PACKAGE 访问权限将被删除。当 Lookup 从一个模块中的类传送到另一个模块时,MODULE 访问权限将被丢弃。跨模块传送会降低在新查找类的模块和旧查找类的模块中访问非导出类的能力,并且生成的 Lookup 仍然只有 PUBLIC 访问权限。一个Lookup可以来回传送到查找类的模块和上一个类查找的模块中的一个类。跨模块传送只能减少访问权限而不能增加访问权限。传送到某个第三个模块会丢弃所有访问权限。

在上面的示例中,如果 CD 在不同的模块中,lookup2D 记录为它的查找类,将 C 记录为其之前的查找类,而 lookup2 只有 PUBLIC 访问权限。 lookup2 可以传送到 C 模块和 D 模块中的其他类。如果类 E 在第三个模块中,则 lookup2.in(E.class)E 上创建一个没有访问权限的 Lookup 并且 lookup2 的查找类 D 被记录为其先前的查找类。

跨模块传送限制了对查找类和前一个查找类可以平等访问的公共类型的访问(见下文)。

MethodHandles.privateLookupIn(T.class, lookup) 可用于将 lookup 从类 C 传送到类 T 并创建一个新的 Lookup私人访问 如果允许查找类在 T 上执行 deep reflectionlookup 必须具有 MODULE PRIVATE 访问权限才能调用 privateLookupIn。允许模块M1C 上的lookupM1 中的所有类进行深度反射。如果 TM1 中,则 privateLookupInT 上生成具有全部功能的新 Lookup。如果M1读取M2M2opens 包含T的包至少M1C上的lookup也被允许对另一个模块M2中的T进行深度反射。 T 成为新的查找类,C 成为新的先前查找类,并且 MODULE 访问从生成的 Lookup 中删除。生成的 Lookup 可用于执行成员查找或通过调用 Lookup::in 传送到另一个查找类。但它不能用于通过调用privateLookupIn 来获取另一个私有Lookup,因为它没有MODULE 访问权限。

跨模块访问检查

Lookup with PUBLIC 或 with UNCONDITIONAL 模式允许跨模块访问。访问检查针对查找类和先前的查找类(如果存在)执行。

当类型位于 无条件出口 包中时,具有 UNCONDITIONAL 模式的 Lookup 可以访问所有模块中的公共类型。

如果 M1 中的 LC 上的 Lookup 没有以前的查找类,则使用 PUBLIC 模式的查找可以访问模块中的所有公共类型,这些类型对 M1 是可读的,并且该类型位于至少导出到 M1 的包中。

如果 M1 中的 LC 上的 LookupM0 上具有先前的查找类 PLC,则使用 PUBLIC 模式的查找可以访问 M1 可访问的所有公共类型与 M0 可访问的所有公共类型的交集。 M0 读取 M1 因此可访问类型集包括:

  • 来自 M1 的无条件导出包
  • 如果 M1 读取 M0,则从 M0 无条件导出包
  • 如果 M0M1 都读取 M2,则从第三个模块 M2 无条件导出包
  • M1M0 限定导出的包
  • 如果 M1 读取 M0,则从 M0M1 的合格出口包
  • 从第三个模块 M2M0M1 的合格导出包,如果 M0M1 都读取 M2

访问模式

下表显示了由以下任何工厂或转换方法生成的Lookup的访问模式:
访问模式总结
查找对象 原来的 protected 私人的 模块 public
CL = MethodHandles.lookup()C ORI PRO PRI PAC MOD 1R
CL.in(C1) 相同的包 PAC MOD 1R
CL.in(C1) 相同的模块 MOD 1R
CL.in(D) 不同的模块 2R
CL.in(D).in(C) 跳回模块 2R
PRI1 = privateLookupIn(C1,CL) PRO PRI PAC MOD 1R
PRI1a = privateLookupIn(C,PRI1) PRO PRI PAC MOD 1R
PRI1.in(C1) 相同的包 PAC MOD 1R
PRI1.in(C1) 不同的包 MOD 1R
PRI1.in(D) 不同的模块 2R
PRI1.dropLookupMode(PROTECTED) PRI PAC MOD 1R
PRI1.dropLookupMode(PRIVATE) PAC MOD 1R
PRI1.dropLookupMode(PACKAGE) MOD 1R
PRI1.dropLookupMode(MODULE) 1R
PRI1.dropLookupMode(PUBLIC) 没有任何
PRI2 = privateLookupIn(D,CL) PRO PRI PAC 2R
privateLookupIn(D,PRI1) PRO PRI PAC 2R
privateLookupIn(C,PRI2) 失败 IAE
PRI2.in(D2) 相同的包 PAC 2R
PRI2.in(D2) 不同的包 2R
PRI2.in(C1) 跳回模块 2R
PRI2.in(E)跳到第三个模块 没有任何
PRI2.dropLookupMode(PROTECTED) PRI PAC 2R
PRI2.dropLookupMode(PRIVATE) PAC 2R
PRI2.dropLookupMode(PACKAGE) 2R
PRI2.dropLookupMode(MODULE) 2R
PRI2.dropLookupMode(PUBLIC) 没有任何
CL.dropLookupMode(PROTECTED) PRI PAC MOD 1R
CL.dropLookupMode(PRIVATE) PAC MOD 1R
CL.dropLookupMode(PACKAGE) MOD 1R
CL.dropLookupMode(MODULE) 1R
CL.dropLookupMode(PUBLIC) 没有任何
PUB = publicLookup() U
PUB.in(D) 不同的模块 U
PUB.in(D).in(E) 第三模块 U
PUB.dropLookupMode(UNCONDITIONAL) 没有任何
privateLookupIn(C1,PUB) 失败 IAE
ANY.in(X) ,用于无法访问的 X 没有任何

笔记:

  • C 和类 C1 在模块 M1 中,但 DD2 在模块 M2 中,E 在模块 M3 中。 X 代表查找无法访问的类。 ANY 代表任何示例查找。
  • ORI 表示ORIGINAL 位设置,PRO 表示PROTECTED 位设置,PRI 表示PRIVATE 位设置,PAC 表示PACKAGE 位设置,MOD 表示MODULE 位设置,_ n140804_ 和 2R 表示 PUBLIC 位设置,U 表示 UNCONDITIONAL 位设置,IAE 表示 IllegalAccessException 抛出。
  • 公共访问分为三种:
    • 无条件(U):查找假定可读性。查找具有 null 先前的查找类。
    • one-module-reads (1R):模块访问检查是针对查找类执行的。查找具有 null 先前的查找类。
    • two-module-reads (2R ):针对查找类和前一个查找类执行模块访问检查。查找有一个非空的先前查找类,它与当前查找类位于不同的模块中。
  • 任何试图到达第三个模块的尝试都会失去所有访问权限。
  • 如果Lookup::in 无法访问目标类X,则所有访问模式都将被删除。

安全管理器交互

尽管字节码指令只能引用相关类加载器中的类,但此 API 可以搜索任何类中的方法,只要对其 Class 对象的引用可用即可。这种交叉加载器引用也可以通过核心反射 API 实现,并且不可能对 invokestaticgetfield 等字节码指令进行编码。有一个 安全管理器API 允许应用程序检查此类交叉加载程序引用。这些检查适用于 MethodHandles.Lookup API 和核心反射 API(在 Class 上找到)。

如果存在安全管理器,则成员和类查找会受到额外检查。安全经理接到了一到三个电话。这些调用中的任何一个都可以通过抛出 SecurityException 来拒绝访问。将 smgr 定义为安全管理器,将 lookc 定义为当前查找对象的查找类,将 refc 定义为查找成员的包含类,将 defc 定义为实际定义成员的类。 (如果正在访问类或其他类型,则 refcdefc 值是类本身。)如果当前查找对象没有 完全权限访问,则值 lookc 定义为 not present。调用是根据以下规则进行的:

  • 步骤1:如果 lookc 不存在,或者如果它的类加载器与 refc 的类加载器不同或不是其祖先,则调用 smgr.checkPackageAccess(refcPkg) ,其中 refcPkgrefc 的包。
  • 步骤 2a:如果检索到的成员不是公开的并且 lookc 不存在,则调用 smgr.checkPermission RuntimePermission("accessDeclaredMembers")
  • 步骤 2b:如果检索到的类具有 null 类加载器,并且 lookc 不存在,则调用 smgr.checkPermission RuntimePermission("getClassLoader")
  • 第 3 步:如果检索到的成员不是公开的,并且 lookc 不存在,并且 defcrefc 不同,则调用 smgr.checkPackageAccess(defcPkg) ,其中 defcPkgdefc 的包。
安全检查在其他访问检查通过后执行。因此,上述规则假定一个成员或类是公共的,或者是从有权访问该成员或类的查找类访问的。

如果存在安全管理器并且当前查找对象没有 完全权限访问,则 defineClass defineHiddenClass defineHiddenClassWithClassData 调用 smgr.checkPermission RuntimePermission("defineClass")

调用者敏感方法

少数 Java 方法具有称为调用者敏感性的特殊属性。 caller-sensitive 方法的行为可能会有所不同,具体取决于其直接调用者的身份。

如果请求调用者敏感方法的方法句柄,则适用 字节码行为 的一般规则,但它们以特殊方式考虑查找类。生成的方法句柄的行为就好像它是从查找类中包含的指令调用的一样,以便调用者敏感的方法检测到查找类。 (相比之下,方法句柄的调用者被忽略。)因此,在调用者敏感方法的情况下,不同的查找类可能会产生不同行为的方法句柄。

在查找对象为 publicLookup() 或不带 原始访问 的其他查找对象的情况下,将忽略查找类。在这种情况下,无法创建对调用者敏感的方法句柄,禁止访问,并且查找失败并返回 IllegalAccessException

Discussion: 例如,调用者敏感方法 Class.forName(x) 可以返回不同的类或抛出不同的异常,具体取决于调用它的类的类加载器。 Class.forName 的公共查找将失败,因为没有合理的方法来确定其字节码行为。

如果应用程序缓存方法句柄以进行广泛共享,则应使用 publicLookup() 来创建它们。如果查找 Class.forName ,它将失败,应用程序必须在这种情况下采取适当的措施。可能是稍后的查找,也许在调用引导方法期间,可以包含调用者的特定身份,从而使该方法可访问。

MethodHandles.lookup 函数对调用者敏感,因此可以为查找奠定安全的基础。 JSR 292 API 中的几乎所有其他方法都依赖查找对象来检查访问请求。

  • 字段详细信息

    • PUBLIC

      public static final int PUBLIC
      表示 public 访问的单位掩码,可能有助于 lookupModes 的结果。值 0x01 恰好与 public 修改位 的值相同。

      具有此查找模式的 Lookup查找类上一个查找类(如果存在)执行跨模块访问检查。

      参见:
    • PRIVATE

      public static final int PRIVATE
      表示 private 访问的单位掩码,可能有助于 lookupModes 的结果。值 0x02 恰好与 private 修改位 的值相同。
      参见:
    • PROTECTED

      public static final int PROTECTED
      表示 protected 访问的单位掩码,可能有助于 lookupModes 的结果。值 0x04 恰好与 protected 修改位 的值相同。
      参见:
    • PACKAGE

      public static final int PACKAGE
      表示 package 访问(默认访问)的单位掩码,这可能有助于 lookupModes 的结果。该值为 0x08,与任何特定的 修改位 没有任何意义对应。
      参见:
    • MODULE

      public static final int MODULE
      表示 module 访问的单位掩码,可能有助于 lookupModes 的结果。该值为 0x10,与任何特定的 修改位 没有任何意义对应。结合PUBLIC修饰符位,具有此查找模式的Lookup可以访问查找类模块中的所有公共类型以及其他模块导出到查找类模块的包中的公共类型。

      如果设置了此查找模式,则 上一个查找类 始终为 null

      自从:
      9
      参见:
    • UNCONDITIONAL

      public static final int UNCONDITIONAL
      表示 unconditional 访问的单位掩码可能有助于 lookupModes 的结果。该值为 0x20,与任何特定的 修改位 没有任何意义对应。具有此查找模式的 Lookup 假定为 可读性。当类型位于 exported unconditionally 包中时,此查找模式可以访问所有模块的公共类型的所有公共成员。

      如果设置了此查找模式,则 上一个查找类 始终为 null

      自从:
      9
      参见:
    • ORIGINAL

      public static final int ORIGINAL
      表示 original 访问的单位掩码可能有助于 lookupModes 的结果。该值为 0x40,与任何特定的 修改位 没有任何意义对应。

      如果设置了此查找模式,Lookup 对象必须由原始查找类通过调用 MethodHandles.lookup() 方法或由 VM 调用的引导程序方法创建。具有此查找模式的 Lookup 对象具有 完全权限访问

      自从:
      16
      参见:
  • 方法详情

    • lookupClass

      public Class <?> lookupClass()
      告诉哪个类正在执行查找。正是针对此类执行可见性和访问权限检查。

      如果此查找对象具有 上一个查找类 ,则会针对查找类和前一个查找类执行访问检查。

      该类意味着最高级别的访问权限,但权限可能会受到位掩码 lookupModes 的额外限制,它控制是否可以访问非公共成员。

      返回:
      查找类,此查找对象代表它查找成员
      参见:
    • previousLookupClass

      public Class <?> previousLookupClass()
      报告另一个模块中的查找类,该查找对象先前是从中传送的,或 null

      由工厂方法(例如 lookup() publicLookup() 方法)生成的 Lookup 对象具有 null 先前的查找类。当此查找从一个模块中的旧查找类传送到另一个模块中的新查找类时,Lookup 对象具有非空的先前查找类。

      返回:
      此查找对象先前从中传送的另一个模块中的查找类,或 null
      自从:
      14
      参见:
    • lookupModes

      public int lookupModes()
      告知此查找对象可以生成哪些成员访问保护类。结果是 PUBLIC (0x01)PRIVATE (0x02)PROTECTED (0x04)PACKAGE (0x08)MODULE (0x10)UNCONDITIONAL (0x20)ORIGINAL (0x40) 位的位掩码。

      调用者类 上新创建的查找对象设置了所有可能的位,UNCONDITIONAL 除外。新查找类 从以前的查找对象创建 上的查找对象可能会将某些模式位设置为零。模式位也可以是 直接清除 。一旦清除,模式位就无法从降级的查找对象中恢复。这样做的目的是限制通过新查找对象的访问,以便它只能访问原始查找对象以及新查找类可以访问的名称。

      返回:
      查找模式,它限制了此查找对象执行的访问类型
      参见:
    • in

      public MethodHandles.Lookup  in(Class <?> requestedLookupClass)
      在指定的新查找类上创建查找。结果对象会将指定的类报告为它自己的 lookupClass

      但是,生成的 Lookup 对象保证不具有比原始对象更多的访问能力。特别是,访问能力可能会丢失如下:

      • 如果新查找类与旧查找类不同,即 ORIGINAL 访问将丢失。
      • 如果新查找类位于与旧查找类不同的模块中,即 MODULE 访问将丢失。
      • 如果新查找类位于与旧查找类不同的包中,则将无法访问受保护和默认(包)成员,即 PROTECTED PACKAGE 访问权丢失。
      • 如果新查找类与旧查找类不在同一个包成员中,则私有成员将不可访问,受保护成员将无法通过继承访问,即PRIVATE 访问丢失。 (由于包共享,受保护的成员可能会继续访问。)
      • 如果新的查找类不是此查找的无障碍,则没有成员,甚至公共成员都不能访问,即所有访问模式都将丢失。
      • 如果新查找类、旧查找类和先前查找类都在不同的模块中,即传送到第三个模块,则所有访问模式都将丢失。

      新的先前查找类选择如下:

      • 如果新的查找对象有 UNCONDITIONAL 位,则新的先前查找类是 null
      • 如果新的查找类与旧的查找类在同一个模块中,则新的先前查找类是旧的先前查找类。
      • 如果新查找类与旧查找类位于不同的模块中,则新的先前查找类是旧查找类。

      生成的查找加载类的能力(在 findClass(java.lang.String) 调用期间使用)由查找类的加载器决定,它可能会因该操作而改变。

      参数:
      requestedLookupClass - 新查找对象所需的查找类
      返回:
      报告所需查找类的查找对象,如果没有更改,则为同一对象
      抛出:
      IllegalArgumentException - 如果 requestedLookupClass 是原始类型或 void 或数组类
      NullPointerException - 如果参数为空
      参见:
    • dropLookupMode

      public MethodHandles.Lookup  dropLookupMode(int modeToDrop)
      在此查找对象找到成员的同一查找类上创建一个查找,但查找模式已丢失给定的查找模式。要删除的查找模式是 PUBLIC MODULE PACKAGE PROTECTED PRIVATE ORIGINAL UNCONDITIONAL 之一。

      如果此查找是 公开查询 ,则此查找已设置 UNCONDITIONAL 模式且未设置其他模式。当在公共查找中删除 UNCONDITIONAL 时,结果查找将无权访问。

      如果此查找不是公共查找,则无论其 查找模式 为何,以下内容均适用。 PROTECTED ORIGINAL 始终被删除,因此生成的查找模式永远不会具有这些访问功能。当删除 PACKAGE 时,结果查找将没有 PACKAGEPRIVATE 访问权限。当删除 MODULE 时,结果查找将没有 MODULEPACKAGEPRIVATE 访问权限。当删除 PUBLIC 时,结果查找将无权访问。

      API 注意:
      使用 PACKAGE 但不是 PRIVATE 模式的查找可以安全地委托查找类包内的非公共访问,而无需授予 私人访问 。使用 MODULE 但不是 PACKAGE 模式的查找可以安全地委托查找类模块内的 PUBLIC 访问,而无需授予包访问权限。使用 上一个查找类(和 PUBLIC 但不是 MODULE 模式)的查找可以安全地委托对查找类的模块和前一个查找类的模块都可以访问的公共类的访问。
      参数:
      modeToDrop - 要删除的查找模式
      返回:
      缺少指示模式的查找对象,或者如果没有更改则为相同的对象
      抛出:
      IllegalArgumentException - 如果 modeToDrop 不是 PUBLICMODULEPACKAGEPROTECTEDPRIVATEORIGINALUNCONDITIONAL 之一
      自从:
      9
      参见:
    • defineClass

      public Class <?> defineClass(byte[] bytes) throws IllegalAccessException
      使用相同的类加载器和相同的运行时包和 保护域 创建并链接来自 bytes 的类或接口作为此查找的 查找类 ,就好像调用 ClassLoader::defineClass 一样。

      此查找的 查找模式 必须包括 PACKAGE 访问,因为默认(包)成员将可供类访问。 PACKAGE 查找模式用于验证查找对象是否由运行时包中的调用者创建(或派生自最初由具有适当特权的代码创建到运行时包中的目标类的查找)。

      bytes 参数是有效类文件(由 The Java Virtual Machine Specification 定义)的类字节,类名与查找类位于同一包中。

      此方法不运行类初始值设定项。类初始值设定项可能会在稍后运行,详见 The Java Language Specification 的第 12.4 节。

      如果有安全管理器并且此查找没有 完全权限访问 ,则首先调用其 checkPermission 方法来检查 RuntimePermission("defineClass")

      参数:
      bytes - 类字节
      返回:
      类的 Class 对象
      抛出:
      IllegalAccessException - 如果此查找没有 PACKAGE 访问权限
      ClassFormatError - 如果 bytes 不是 ClassFile 结构
      IllegalArgumentException - 如果 bytes 表示与查找类不同的包中的类,或者 bytes 不是类或接口(ACC_MODULE 标志在 access_flags 项的值中设置)
      VerifyError - 如果无法验证新创建的类
      LinkageError - 如果由于任何其他原因无法链接新创建的类
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果 bytesnull
      自从:
      9
      参见:
    • defineHiddenClass

      public MethodHandles.Lookup  defineHiddenClass(byte[] bytes, boolean initialize, MethodHandles.Lookup.ClassOption ... options) throws IllegalAccessException
      bytes 创建一个 hidden 类或接口,在新创建的类或接口上返回一个 Lookup

      通常,类或接口 C 由类加载器创建,类加载器直接定义 C 或委托给另一个类加载器。类加载器通过调用 ClassLoader::defineClass 直接定义 C,这会导致 Java 虚拟机从 class 文件格式的声称表示派生 C。在不希望使用类加载器的情况下,可以通过此方法创建类或接口 C。此方法能够定义 C ,从而创建它,而无需调用 ClassLoader::defineClass 。相反,此方法定义 C 就好像通过安排 Java 虚拟机使用以下规则从 class 文件格式的声称表示派生非数组类或接口 C 一样:

      1. Lookup查找模式 必须包含 完全特权 访问权限。需要此访问级别才能在此 Lookup 的查找类的模块中创建 C
      2. bytes 中声称的表示必须是受支持的主要和次要版本的 ClassFile 结构(JVMS 4.1)。主要版本和次要版本可能与此 Lookup 的查找类的 class 文件版本不同。
      3. this_class 的值必须是 constant_pool 表中的有效索引,并且该索引处的条目必须是有效的 CONSTANT_Class_info 结构。设 N 为该结构指定的以内部形式编码的二进制名称。 N 必须表示与查找类位于同一包中的类或接口。
      4. CN 成为字符串 N + "." + <suffix> ,其中 <suffix> 是一个非限定名称。

        newBytesbytes 给出的 ClassFile 结构,并在 constant_pool 表中添加了一个条目,指示 CNCONSTANT_Utf8_info 结构,其中 this_class 指示的 CONSTANT_Class_info 结构指的是新的 CONSTANT_Utf8_info 结构。

        L 成为这个 Lookup 的查找类的定义类加载器。

        C 的派生名称为 CN ,类加载器为 L ,声称的表示形式为 newBytes ,就像 JVMS 5.3.5 的规则一样,并进行了以下调整:

        • this_class 指示的常量允许指定包含单个 "." 字符的名称,即使这不是内部形式的有效二进制类或接口名称。
        • Java 虚拟机将 L 标记为 C 的定义类加载器,但没有类加载器被记录为 C 的初始类加载器。
        • C 被认为具有与此 Lookup 的查找类相同的运行时 module保护域
        • GN 是通过采用 N(以内部形式编码的二进制名称)并将 ASCII 正斜杠替换为 ASCII 句点而获得的二进制名称。对于代表 CClass 实例:

      C 派生后,由 Java 虚拟机链接。链接按照 JVMS 5.4.3 中的规定进行,并进行了以下调整:

      • 在验证期间,每当需要加载名为 CN 的类时,尝试都会成功,生成类 C。没有请求任何类加载器。
      • 在任何尝试解析 this_class 指示的运行时常量池中的条目时,符号引用被认为已解析为 C 并且解析总是立即成功。

      如果 initialize 参数为 true ,则 C 由 Java 虚拟机初始化。

      新创建的类或接口 C 充当此方法返回的 Lookup 对象的 查找类Chidden,因为没有其他类或接口可以通过常量池条目引用 C。也就是说,隐藏类或接口不能被任何其他类命名为超类型、字段类型、方法参数类型或方法返回类型。这是因为隐藏类或接口没有二进制名称,因此在任何类的常量池中都没有可用的内部形式来记录。 Class.forName(String, boolean, ClassLoader) ClassLoader.loadClass(String, boolean) findClass(String) 无法发现隐藏类或接口,Java 代理或使用 JVM 工具接口 的工具代理也无法发现隐藏类或接口。

      类加载器 创建的类或接口与该类加载器有很强的关系。也就是说,每个 Class 对象都包含对 ClassLoader定义它 的引用。这意味着当且仅当它的定义加载器不可访问时,由类加载器创建的类才可以被卸载,因此可以被垃圾收集器回收 (JLS 12.7)。但是,默认情况下,即使标记为定义加载器的类加载器是 可达的 ,也可以卸载隐藏类或接口。当隐藏类或接口服务于任意类加载器定义的多个类时,此行为很有用。在其他情况下,隐藏类或接口可以链接到具有与隐藏类或接口相同的定义加载器的单个类(或少量类)。在这种情况下,隐藏类或接口必须与普通类或接口相连,可以在 options 中传递 STRONG 选项。这安排隐藏类与标记为其定义加载器的类加载器具有相同的强关系,就像普通类或接口与其自己的定义加载器一样。如果未使用 STRONG,则 defineHiddenClass 的调用者仍可通过确保 Class 对象可访问来阻止隐藏类或接口被卸载。

      卸载特性在定义时为每个隐藏类设置,以后不能更改。允许独立于标记为定义加载器的类加载器卸载隐藏类的一个优点是应用程序可能会创建大量隐藏类。相反,如果使用 STRONG,那么 JVM 可能会耗尽内存,就好像普通类是由类加载器创建的一样。

      允许嵌套中的类和接口相互访问它们的私有成员。嵌套关系由 class 文件中的 NestHost 属性 (JVMS 4.7.28 ) 和 NestMembers 属性 (JVMS 4.7.29 ) 确定。默认情况下,隐藏类属于仅由其自身组成的嵌套,因为隐藏类没有二进制名称。 NESTMATE 选项可以传入 options 以创建隐藏类或接口 C 作为嵌套成员。 C 所属的嵌套不基于派生 CClassFile 结构中的任何 NestHost 属性。相反,以下规则确定 C 的嵌套主机:

      • 如果之前已经确定了这个Lookup的查找类的嵌套宿主,那么让H成为查找类的嵌套宿主。否则,使用 JVMS 中的算法确定查找类的嵌套主机 5.4.4 ,产生 H
      • C 的嵌套主机被确定为 H,查找类的嵌套主机。

      隐藏的类或接口可能是可序列化的,但这需要自定义序列化机制以确保实例被正确序列化和反序列化。默认序列化机制仅支持可通过类名发现的类和接口。

      参数:
      bytes - 构成类数据的字节,采用由定义的有效 class 文件的格式Java 虚拟机规范.
      initialize - 如果 true 类将被初始化。
      options - 类选项
      返回:
      隐藏类上的 Lookup 对象,具有 原来的完全特权 访问权限
      抛出:
      IllegalAccessException - 如果这个 Lookup 没有 完全特权 访问权限
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      ClassFormatError - 如果 bytes 不是 ClassFile 结构
      UnsupportedClassVersionError - 如果 bytes 不是受支持的主要或次要版本
      IllegalArgumentException - 如果 bytes 表示与查找类不同的包中的类,或者 bytes 不是类或接口(ACC_MODULE 标志在 access_flags 项的值中设置)
      IncompatibleClassChangeError - 如果命名为 C 的直接超类的类或接口实际上是一个接口,或者如果命名为 C 的直接超类的任何类或接口实际上不是接口
      ClassCircularityError - 如果 C 的任何超类或超接口是 C 本身
      VerifyError - 如果无法验证新创建的类
      LinkageError - 如果由于任何其他原因无法链接新创建的类
      NullPointerException - 如果任何参数是 null
      Java 语言规范:
      12.7 类和接口的卸载
      Java 虚拟机规范:
      4.2.1 二进制类和接口名称
      4.2.2 非限定名称
      4.7.28NestHost属性
      4.7.29NestMembers属性
      5.4.3.1 类和接口解析
      5.4.4 访问控制
      5.3.5 从 文件表示中导出 Class
      5.4 链接
      5.5 初始化
      自从:
      15
      参见:
    • defineHiddenClassWithClassData

      public MethodHandles.Lookup  defineHiddenClassWithClassData(byte[] bytes, Object  classData, boolean initialize, MethodHandles.Lookup.ClassOption ... options) throws IllegalAccessException
      bytes 和关联的 类数据 创建一个 hidden 类或接口,在新创建的类或接口上返回一个 Lookup

      这个方法相当于调用defineHiddenClass(bytes, initialize, options) 就好像隐藏类注入了private static final无名在类初始化程序的第一条指令中使用给定的 classData 初始化的字段。新创建的类由 Java 虚拟机链接。

      MethodHandles::classData MethodHandles::classDataAt 方法可用于检索 classData

      API 注意:
      框架可以创建一个隐藏类,其中包含一个或多个对象的类数据,并通过引导方法将类数据加载为动态计算的常量。 Class data 只能由新定义的隐藏类创建的查找对象访问,但同一嵌套中的其他成员无法访问(与 nestmates 可访问的私有静态字段不同)。应该注意可变性,例如在通过类数据传递数组或其他可变结构时。在运行时更改存储在类数据中的任何值可能会导致不可预知的行为。如果类数据是 List ,最好使其不可修改,例如通过 List::of
      参数:
      bytes - 类字节
      classData - 预初始化类数据
      initialize - 如果 true 类将被初始化。
      options - 类选项
      返回:
      隐藏类上的 Lookup 对象,具有 原来的完全特权 访问权限
      抛出:
      IllegalAccessException - 如果这个 Lookup 没有 完全特权 访问权限
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      ClassFormatError - 如果 bytes 不是 ClassFile 结构
      UnsupportedClassVersionError - 如果 bytes 不是受支持的主要或次要版本
      IllegalArgumentException - 如果 bytes 表示与查找类不同的包中的类,或者 bytes 不是类或接口(ACC_MODULE 标志在 access_flags 项的值中设置)
      IncompatibleClassChangeError - 如果命名为 C 的直接超类的类或接口实际上是一个接口,或者如果命名为 C 的直接超类的任何类或接口实际上不是接口
      ClassCircularityError - 如果 C 的任何超类或超接口是 C 本身
      VerifyError - 如果无法验证新创建的类
      LinkageError - 如果由于任何其他原因无法链接新创建的类
      NullPointerException - 如果任何参数是 null
      Java 语言规范:
      12.7 类和接口的卸载
      Java 虚拟机规范:
      4.2.1 二进制类和接口名称
      4.2.2 非限定名称
      4.7.28NestHost属性
      4.7.29NestMembers属性
      5.4.3.1 类和接口解析
      5.4.4 访问控制
      5.3.5 从 文件表示中导出 Class
      5.4 链接
      5.5 初始化
      自从:
      16
      参见:
    • toString

      public String  toString()
      显示要从中进行查找的类的名称,后跟“/”和 上一个查找类 的名称(如果存在)。 (该名称是由 Class.getName 报告的名称。)如果对该查找允许的访问有限制,则通过向类名添加一个后缀来表示,该后缀由一个斜杠和一个关键字组成。关键字代表最强的允许访问,选择如下:
      • 如果不允许访问,则后缀为“/noaccess”。
      • 如果只允许无条件访问,则后缀为“/publicLookup”。
      • 如果仅允许公开访问导出包中的类型,则后缀为“/public”。
      • 如果只允许公共和模块访问,则后缀为“/module”。
      • 如果允许公共和包访问,则后缀为“/package”。
      • 如果允许 public、package 和 private 访问,则后缀为“/private”。
      如果以上情况都不适用,则允许完全权限访问(公共、模块、包、私有和受保护)。在这种情况下,不添加后缀。这仅适用于最初从 MethodHandles.lookup 获得的对象。 Lookup.in 创建的对象始终具有受限访问权限,并将显示后缀。

      (protected access 应该比 private access 更强,这似乎很奇怪。独立于 package access 来看,protected access 是最先丢失的,因为它需要调用者和被调用者之间有直接的子类关系。)

      重写:
      toString 在类 Object
      返回:
      对象的字符串表示形式。
      参见:
    • findStatic

      public MethodHandle  findStatic(Class <?> refc, String  name, MethodType  type) throws NoSuchMethodException , IllegalAccessException
      为静态方法生成方法句柄。方法句柄的类型将是方法的类型。 (由于静态方法不接受接收器,因此没有额外的接收器参数插入到方法句柄类型中,就像 findVirtual findSpecial 那样。)查找对象必须可以访问该方法及其所有参数类型。

      当且仅当设置了方法的可变元数修饰符位 (0x0080) 时,返回的方法句柄将具有 变数

      如果返回的方法句柄被调用,方法的类将被初始化,如果它还没有被初始化的话。

      示例:

      import static java.lang.invoke.MethodHandles.*;
      import static java.lang.invoke.MethodType.*;
      ...
      MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
       "asList", methodType(List.class, Object[].class));
      assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
       
      参数:
      refc - 访问该方法的类
      name - 方法的名称
      type - 方法的类型
      返回:
      所需的方法句柄
      抛出:
      NoSuchMethodException - 如果该方法不存在
      IllegalAccessException - 如果访问检查失败,或者如果方法不是 static ,或者如果设置了方法的变量 arity 修饰符位并且 asVarargsCollector 失败
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果任何参数为空
    • findVirtual

      public MethodHandle  findVirtual(Class <?> refc, String  name, MethodType  type) throws NoSuchMethodException , IllegalAccessException
      为虚拟方法生成方法句柄。方法句柄的类型将是方法的类型,并在前面加上接收者类型(通常是 refc )。查找对象必须可以访问该方法及其所有参数类型。

      调用时,句柄会将第一个参数视为接收者,并且对于非私有方法,将根据接收者的类型进行分派以确定进入哪个方法实现。对于私有方法,refc 中的命名方法将在接收者上调用。 (调度操作与 invokevirtualinvokeinterface 指令执行的操作相同。)

      如果查找类具有访问该成员的全部权限,则第一个参数的类型为 refc。否则该成员必须是 protected 并且第一个参数的类型将被限制为查找类。

      当且仅当设置了方法的可变元数修饰符位 (0x0080) 时,返回的方法句柄将具有 变数

      由于 invokevirtual 指令和 findVirtual 生成的方法句柄之间的通用 等价,如果类为 MethodHandle 并且名称字符串为 invokeExactinvoke,则生成的方法句柄等同于由 MethodHandles.exactInvoker MethodHandles.invoker 生成的具有相同 _n607 的方法句柄8_ 论点。

      如果类是 VarHandle 并且名称字符串对应于签名多态访问模式方法的名称,则生成的方法句柄等效于 MethodHandles.varHandleInvoker(java.lang.invoke.VarHandle.AccessMode, java.lang.invoke.MethodType) 生成的方法句柄,其访问模式对应于名称字符串并具有相同的 type 参数。

      示例:

      import static java.lang.invoke.MethodHandles.*;
      import static java.lang.invoke.MethodType.*;
      ...
      MethodHandle MH_concat = publicLookup().findVirtual(String.class,
       "concat", methodType(String.class, String.class));
      MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
       "hashCode", methodType(int.class));
      MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
       "hashCode", methodType(int.class));
      assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
      assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
      assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
      // interface method:
      MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
       "subSequence", methodType(CharSequence.class, int.class, int.class));
      assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
      // constructor "internal method" must be accessed differently:
      MethodType MT_newString = methodType(void.class); //()V for new String()
      try { assertEquals("impossible", lookup()
          .findVirtual(String.class, "<init>", MT_newString));
       } catch (NoSuchMethodException ex) { } // OK
      MethodHandle MH_newString = publicLookup()
       .findConstructor(String.class, MT_newString);
      assertEquals("", (String) MH_newString.invokeExact());
       
      参数:
      refc - 访问方法的类或接口
      name - 方法的名称
      type - 方法的类型,省略了接收者参数
      返回:
      所需的方法句柄
      抛出:
      NoSuchMethodException - 如果该方法不存在
      IllegalAccessException - 如果访问检查失败,或者如果方法是 static ,或者如果设置了方法的变量 arity 修饰符位并且 asVarargsCollector 失败
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果任何参数为空
    • findConstructor

      public MethodHandle  findConstructor(Class <?> refc, MethodType  type) throws NoSuchMethodException , IllegalAccessException
      使用指定类型的构造方法生成一个方法句柄,该句柄创建一个对象并对其进行初始化。方法句柄的参数类型将是构造方法的参数类型,而返回类型将是对构造方法类的引用。查找对象必须可以访问构造方法及其所有参数类型。

      请求的类型必须具有 void 的返回类型。 (这与 JVM 对构造函数类型描述符的处理方式一致。)

      当且仅当构造函数的可变元数修饰符位 (0x0080) 已设置时,返回的方法句柄将具有 变数

      如果返回的方法句柄被调用,构造方法的类将被初始化,如果它还没有被初始化的话。

      示例:

      import static java.lang.invoke.MethodHandles.*;
      import static java.lang.invoke.MethodType.*;
      ...
      MethodHandle MH_newArrayList = publicLookup().findConstructor(
       ArrayList.class, methodType(void.class, Collection.class));
      Collection orig = Arrays.asList("x", "y");
      Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
      assert(orig != copy);
      assertEquals(orig, copy);
      // a variable-arity constructor:
      MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
       ProcessBuilder.class, methodType(void.class, String[].class));
      ProcessBuilder pb = (ProcessBuilder)
       MH_newProcessBuilder.invoke("x", "y", "z");
      assertEquals("[x, y, z]", pb.command().toString());
       
      参数:
      refc - 访问方法的类或接口
      type - 方法的类型,省略了接收者参数,返回类型为 void
      返回:
      所需的方法句柄
      抛出:
      NoSuchMethodException - 如果构造函数不存在
      IllegalAccessException - 如果访问检查失败或者如果设置了方法的变量 arity 修饰符位并且 asVarargsCollector 失败
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果任何参数为空
    • findClass

      public Class <?> findClass(String  targetName) throws ClassNotFoundException , IllegalAccessException
      从此 Lookup 对象定义的查找上下文中按名称查找类,通过 ldc 指令 仿佛解决了。这种解决方案,如 JVMS 5.4.3.1 中所指定,尝试定位并加载类,然后确定该查找对象是否可以访问该类。

      此处的查找上下文由 查找类 、它的类加载器和 查找模式 确定。

      参数:
      targetName - 要查找的类的完全限定名称。
      返回:
      请求的类。
      抛出:
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      LinkageError - 如果链接失败
      ClassNotFoundException - 如果查找类的加载器无法加载该类。
      IllegalAccessException - 如果该类不可访问,则使用允许的访问模式。
      NullPointerException - 如果 targetName 为空
      Java 虚拟机规范:
      5.4.3.1 类和接口解析
      自从:
      9
    • ensureInitialized

      public Class <?> ensureInitialized(Class <?> targetClass) throws IllegalAccessException
      确保 targetClass 已被初始化。要初始化的类必须是无障碍到这个Lookup对象。如果 targetClass 尚未按照 JVMS 5.5 中的规定进行初始化,则此方法会导致对其进行初始化。

      targetClass 完全初始化时,或者当 targetClass 正在被当前线程初始化时,此方法返回。

      参数:
      targetClass - 要初始化的类
      返回:
      targetClass 已经初始化,或者正在被当前线程初始化。
      抛出:
      IllegalArgumentException - 如果 targetClass 是原始类型或 void 或数组类
      IllegalAccessException - 如果 targetClass 不是此查找的 无障碍
      ExceptionInInitializerError - 如果此方法引发的类初始化失败
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      Java 虚拟机规范:
      5.5 初始化
      自从:
      15
    • accessClass

      public Class <?> accessClass(Class <?> targetClass) throws IllegalAccessException
      确定是否可以从此 Lookup 对象定义的查找上下文访问类。类的静态初始值设定项未运行。如果targetClass 是数组类,则如果数组类的元素类型是可访问的,则targetClass 是可访问的。否则,targetClass 被确定为可访问,如下所示。

      如果 targetClass 与查找类位于同一模块中,则查找类是模块 M1 中的 LC 并且前一个查找类位于模块 M0null 中(如果不存在),当且仅当以下其中一项为真时,targetClass 才可访问:

      • 如果此查找具有 PRIVATE 访问权限,则 targetClassLCLC 同一嵌套中的其他类。
      • 如果此查找具有 PACKAGE 访问权限,则 targetClass 位于 LC 的同一运行时包中。
      • 如果此查找具有 MODULE 访问权限,则 targetClassM1 中的公共类型。
      • 如果此查找具有 PUBLIC 访问权限,则 targetClass 是包中的公共类型,由 M1 导出到至少 M0(如果存在前一个查找类);否则,targetClassM1 无条件导出的包中的公共类型。

      否则,如果此查找具有 UNCONDITIONAL 访问权限,则当类型位于无条件导出的包中时,此查找可以访问所有模块中的公共类型。

      否则,targetClasslookupClass 在不同的模块中,如果此查找没有 PUBLIC 访问权限,则 lookupClass 不可访问。

      否则,如果此查找没有 上一个查找类M1 是包含 lookupClass 的模块,M2 是包含 targetClass 的模块,那么 targetClass 是可访问的当且仅当

      • M1 读取 M2,并且
      • targetClass 是公开的,并且在 M2 至少导出到 M1 的包中。

      否则,如果此查找有一个 上一个查找类M1M2 和以前一样,并且 M0 是包含前一个查找类的模块,那么 targetClass 是可访问的当且仅当以下条件之一为真:

      • targetClassM0M1 读取 M0 并且类型在至少导出到 M1 的包中。
      • targetClassM1M0 读取 M1 并且类型在至少导出到 M0 的包中。
      • targetClass 在第三个模块 M2 中,M0M1 都读取 M2 并且该类型位于至少导出到 M0M2 的包中。

      否则,targetClass 不可访问。

      参数:
      targetClass - 要进行访问检查的类
      返回:
      已经过访问检查的类
      抛出:
      IllegalAccessException - 如果无法使用允许的访问模式从查找类和先前的查找类(如果存在)访问该类。
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果 targetClassnull
      自从:
      9
      参见:
    • findSpecial

      public MethodHandle  findSpecial(Class <?> refc, String  name, MethodType  type, Class <?> specialCaller) throws NoSuchMethodException , IllegalAccessException
      为虚拟方法生成早期绑定方法句柄。它将绕过对接收方覆盖方法的检查,好像被称为 来自显式指定的 specialCaller 中的 invokespecial 指令。方法句柄的类型将是方法的类型,并在前面加上适当限制的接收器类型。 (接收者类型将为 specialCaller 或子类型。)查找对象必须可以访问该方法及其所有参数类型。

      在方法解析之前,如果显式指定的调用者类与查找类不相同,或者如果此查找对象不具有私人访问权限,则访问失败。

      当且仅当设置了方法的可变元数修饰符位 (0x0080) 时,返回的方法句柄将具有 变数

      (Note: JVM internal methods named "<init>" are not visible to this API, even though the invokespecial instruction can refer to them in special circumstances. Use findConstructor to access instance initialization methods in a safe manner.)

      示例:

      import static java.lang.invoke.MethodHandles.*;
      import static java.lang.invoke.MethodType.*;
      ...
      static class Listie extends ArrayList {
       public String toString() { return "[wee Listie]"; }
       static Lookup lookup() { return MethodHandles.lookup(); }
      }
      ...
      // no access to constructor via invokeSpecial:
      MethodHandle MH_newListie = Listie.lookup()
       .findConstructor(Listie.class, methodType(void.class));
      Listie l = (Listie) MH_newListie.invokeExact();
      try { assertEquals("impossible", Listie.lookup().findSpecial(
          Listie.class, "<init>", methodType(void.class), Listie.class));
       } catch (NoSuchMethodException ex) { } // OK
      // access to super and self methods via invokeSpecial:
      MethodHandle MH_super = Listie.lookup().findSpecial(
       ArrayList.class, "toString" , methodType(String.class), Listie.class);
      MethodHandle MH_this = Listie.lookup().findSpecial(
       Listie.class, "toString" , methodType(String.class), Listie.class);
      MethodHandle MH_duper = Listie.lookup().findSpecial(
       Object.class, "toString" , methodType(String.class), Listie.class);
      assertEquals("[]", (String) MH_super.invokeExact(l));
      assertEquals(""+l, (String) MH_this.invokeExact(l));
      assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
      try { assertEquals("inaccessible", Listie.lookup().findSpecial(
          String.class, "toString", methodType(String.class), Listie.class));
       } catch (IllegalAccessException ex) { } // OK
      Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
      assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
       
      参数:
      refc - 访问方法的类或接口
      name - 方法的名称(不能是“<init>”)
      type - 方法的类型,省略了接收者参数
      specialCaller - 建议的调用类来执行 invokespecial
      返回:
      所需的方法句柄
      抛出:
      NoSuchMethodException - 如果该方法不存在
      IllegalAccessException - 如果访问检查失败,或者如果方法是 static ,或者如果设置了方法的变量 arity 修饰符位并且 asVarargsCollector 失败
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果任何参数为空
    • findGetter

      public MethodHandle  findGetter(Class <?> refc, String  name, Class <?> type) throws NoSuchFieldException , IllegalAccessException
      生成一个方法句柄,提供对非静态字段的读取访问权限。方法句柄的类型将具有字段值类型的返回类型。方法句柄的单个参数将是包含该字段的实例。代表查找类立即执行访问检查。
      参数:
      refc - 访问方法的类或接口
      name - 字段名称
      type - 字段的类型
      返回:
      可以从字段加载值的方法句柄
      抛出:
      NoSuchFieldException - 如果字段不存在
      IllegalAccessException - 如果访问检查失败,或者字段为 static
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果任何参数为空
      参见:
    • findSetter

      public MethodHandle  findSetter(Class <?> refc, String  name, Class <?> type) throws NoSuchFieldException , IllegalAccessException
      生成一个方法句柄,提供对非静态字段的写访问权限。方法句柄的类型将具有 void 返回类型。方法句柄将采用两个参数,包含字段的实例和要存储的值。第二个参数将是字段的值类型。代表查找类立即执行访问检查。
      参数:
      refc - 访问方法的类或接口
      name - 字段名称
      type - 字段的类型
      返回:
      可以将值存储到字段中的方法句柄
      抛出:
      NoSuchFieldException - 如果字段不存在
      IllegalAccessException - 如果访问检查失败,或者字段为 staticfinal
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果任何参数为空
      参见:
    • findVarHandle

      public VarHandle  findVarHandle(Class <?> recv, String  name, Class <?> type) throws NoSuchFieldException , IllegalAccessException
      生成一个 VarHandle,允许访问类型为 recv 的类中声明的类型为 type 的非静态字段 name。 VarHandle 的变量类型是 type,它有一个坐标类型,recv

      代表查找类立即执行访问检查。

      在以下情况下,不支持返回的 VarHandle 的某些访问模式:

      • 如果该字段声明为 final ,则不支持写入、原子更新、数字原子更新和按位原子更新访问模式。
      • 如果字段类型不是 byteshortcharintlongfloatdouble,则不支持数字原子更新访问模式。
      • 如果字段类型不是 booleanbyteshortcharintlong,则不支持按位原子更新访问模式。

      如果该字段声明为 volatile,则返回的 VarHandle 将根据其指定的访问模式覆盖对该字段的访问(有效地忽略 volatile 声明)。

      如果字段类型是 floatdouble,则数字和原子更新访问模式使用它们的按位表示比较值(分别参见 Float.floatToRawIntBits(float) Double.doubleToRawLongBits(double) )。

      API 注意:
      float 值或 double 值的按位比较,由数字和原子更新访问模式执行,不同于原始 == 运算符以及 Float.equals(java.lang.Object) Double.equals(java.lang.Object) 方法,特别是比较 NaN 值或比较 -0.0+0.0 。在使用此类值执行比较和设置或比较和交换操作时应小心,因为操作可能会意外失败。有许多可能的 NaN 值在 Java 中被认为是 NaN,尽管 Java 提供的 IEEE 754 浮点运算无法区分它们。如果预期或见证值是 NaN 值并且它被转换(可能以特定于平台的方式)为另一个 NaN 值,并且因此具有不同的按位表示(请参阅 Float.intBitsToFloat(int) Double.longBitsToDouble(long) 了解更多详细信息),则可能会发生操作失败。值 -0.0+0.0 具有不同的按位表示,但在使用原始 == 运算符时被视为相等。例如,如果数字算法计算的预期值为 -0.0 并且先前计算的见证值为 +0.0 ,则可能会发生操作失败。
      参数:
      recv - 类型为 R 的接收器类,它声明了非静态字段
      name - 字段名称
      type - 字段类型,类型为 T
      返回:
      允许访问非静态字段的 VarHandle。
      抛出:
      NoSuchFieldException - 如果字段不存在
      IllegalAccessException - 如果访问检查失败,或者字段为 static
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果任何参数为空
      自从:
      9
    • findStaticGetter

      public MethodHandle  findStaticGetter(Class <?> refc, String  name, Class <?> type) throws NoSuchFieldException , IllegalAccessException
      生成一个方法句柄,提供对静态字段的读取访问权限。方法句柄的类型将具有字段值类型的返回类型。方法句柄将不带任何参数。代表查找类立即执行访问检查。

      如果调用返回的方法句柄,则字段的类将被初始化(如果尚未初始化)。

      参数:
      refc - 访问方法的类或接口
      name - 字段名称
      type - 字段的类型
      返回:
      可以从字段加载值的方法句柄
      抛出:
      NoSuchFieldException - 如果字段不存在
      IllegalAccessException - 如果访问检查失败,或者字段不是 static
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果任何参数为空
    • findStaticSetter

      public MethodHandle  findStaticSetter(Class <?> refc, String  name, Class <?> type) throws NoSuchFieldException , IllegalAccessException
      生成一个方法句柄,提供对静态字段的写访问权。方法句柄的类型将具有 void 返回类型。方法句柄将采用字段值类型的单个参数,即要存储的值。代表查找类立即执行访问检查。

      如果调用返回的方法句柄,则字段的类将被初始化(如果尚未初始化)。

      参数:
      refc - 访问方法的类或接口
      name - 字段名称
      type - 字段的类型
      返回:
      可以将值存储到字段中的方法句柄
      抛出:
      NoSuchFieldException - 如果字段不存在
      IllegalAccessException - 如果访问检查失败,或者字段不是 staticfinal
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果任何参数为空
    • findStaticVarHandle

      public VarHandle  findStaticVarHandle(Class <?> decl, String  name, Class <?> type) throws NoSuchFieldException , IllegalAccessException
      生成一个 VarHandle,允许访问类型为 decl 的类中声明的类型为 type 的静态字段 name。 VarHandle 的变量类型是type,没有坐标类型。

      代表查找类立即执行访问检查。

      如果对返回的 VarHandle 进行操作,则声明类将被初始化(如果尚未初始化)。

      在以下情况下,不支持返回的 VarHandle 的某些访问模式:

      • 如果该字段声明为 final ,则不支持写入、原子更新、数字原子更新和按位原子更新访问模式。
      • 如果字段类型不是 byteshortcharintlongfloatdouble,则不支持数字原子更新访问模式。
      • 如果字段类型不是 booleanbyteshortcharintlong,则不支持按位原子更新访问模式。

      如果该字段声明为 volatile,则返回的 VarHandle 将根据其指定的访问模式覆盖对该字段的访问(有效地忽略 volatile 声明)。

      如果字段类型是 floatdouble,则数字和原子更新访问模式使用它们的按位表示比较值(分别参见 Float.floatToRawIntBits(float) Double.doubleToRawLongBits(double) )。

      API 注意:
      float 值或 double 值的按位比较,由数字和原子更新访问模式执行,不同于原始 == 运算符以及 Float.equals(java.lang.Object) Double.equals(java.lang.Object) 方法,特别是比较 NaN 值或比较 -0.0+0.0 。在使用此类值执行比较和设置或比较和交换操作时应小心,因为操作可能会意外失败。有许多可能的 NaN 值在 Java 中被认为是 NaN,尽管 Java 提供的 IEEE 754 浮点运算无法区分它们。如果预期或见证值是 NaN 值并且它被转换(可能以特定于平台的方式)为另一个 NaN 值,并且因此具有不同的按位表示(请参阅 Float.intBitsToFloat(int) Double.longBitsToDouble(long) 了解更多详细信息),则可能会发生操作失败。值 -0.0+0.0 具有不同的按位表示,但在使用原始 == 运算符时被视为相等。例如,如果数字算法计算的预期值为 -0.0 并且先前计算的见证值为 +0.0 ,则可能会发生操作失败。
      参数:
      decl - 声明静态字段的类
      name - 字段名称
      type - 字段类型,类型为 T
      返回:
      允许访问静态字段的 VarHandle
      抛出:
      NoSuchFieldException - 如果字段不存在
      IllegalAccessException - 如果访问检查失败,或者字段不是 static
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果任何参数为空
      自从:
      9
    • bind

      public MethodHandle  bind(Object  receiver, String  name, MethodType  type) throws NoSuchMethodException , IllegalAccessException
      为非静态方法生成早期绑定方法句柄。接收者必须有一个超类型defc,其中给定名称和类型的方法可供查找类访问。查找对象必须可以访问该方法及其所有参数类型。方法句柄的类型将是方法的类型,无需插入任何额外的接收者参数。给定的接收器将绑定到方法句柄中,因此每次调用方法句柄都会调用给定接收器上请求的方法。

      返回的方法句柄将具有 变数 当且仅当方法的变量 arity 修饰符位 (0x0080) 被设置时 and 尾随数组参数不是唯一的参数。 (如果尾随数组参数是唯一的参数,则给定的接收者值将绑定到它。)

      这几乎等同于以下代码,但有一些区别如下:

      import static java.lang.invoke.MethodHandles.*;
      import static java.lang.invoke.MethodType.*;
      ...
      MethodHandle mh0 = lookup().findVirtual(defc, name, type);
      MethodHandle mh1 = mh0.bindTo(receiver);
      mh1 = mh1.withVarargs(mh0.isVarargsCollector());
      return mh1;
       
      其中 defcreceiver.getClass() 或该类的超类型,其中查找类可以访问请求的方法。 (与 bind 不同,bindTo 不保留变量元数。此外,bindTo 可能会在 bind 会抛出 IllegalAccessException 的情况下抛出 ClassCastException,就像成员是 protected 并且接收者被 findVirtual 限制到查找类的情况一样。)
      参数:
      receiver - 访问该方法的对象
      name - 方法的名称
      type - 方法的类型,省略了接收者参数
      返回:
      所需的方法句柄
      抛出:
      NoSuchMethodException - 如果该方法不存在
      IllegalAccessException - 如果访问检查失败或者如果设置了方法的变量 arity 修饰符位并且 asVarargsCollector 失败
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      NullPointerException - 如果任何参数为空
      参见:
    • unreflect

      public MethodHandle  unreflect(Method  m) throws IllegalAccessException
      制作一个 直接方法句柄m,如果查找类具有权限。如果m是非静态的,接收者参数被视为初始参数。如果m是虚拟的,每次调用都尊重重写。与 Core Reflection API 不同,异常是 not 包装的。方法句柄的类型将是方法的类型,并在前面加上接收者类型(但前提是它是非静态的)。如果未设置方法的accessible 标志,则代表查找类立即执行访问检查。如果m不公开,请勿与不受信任的方共享生成的句柄。

      当且仅当设置了方法的可变元数修饰符位 (0x0080) 时,返回的方法句柄将具有 变数

      如果m是静态的,如果返回的方法句柄被调用,方法的类将被初始化,如果它还没有被初始化的话。

      参数:
      m - 反射方法
      返回:
      可以调用反射方法的方法句柄
      抛出:
      IllegalAccessException - 如果访问检查失败或者如果设置了方法的变量 arity 修饰符位并且 asVarargsCollector 失败
      NullPointerException - 如果参数为空
    • unreflectSpecial

      public MethodHandle  unreflectSpecial(Method  m, Class <?> specialCaller) throws IllegalAccessException
      为反射方法生成方法句柄。它将绕过对接收方覆盖方法的检查,好像被称为 来自显式指定的 specialCaller 中的 invokespecial 指令。方法句柄的类型将是方法的类型,并在前面加上适当限制的接收器类型。 (接收者类型将为 specialCaller 或子类型。)如果未设置方法的 accessible 标志,则代表查找类立即执行访问检查,就好像 invokespecial 指令被链接一样。

      在方法解析之前,如果显式指定的调用者类与查找类不相同,或者如果此查找对象不具有私人访问权限,则访问失败。

      当且仅当设置了方法的可变元数修饰符位 (0x0080) 时,返回的方法句柄将具有 变数

      参数:
      m - 反射方法
      specialCaller - 名义上调用方法的类
      返回:
      可以调用反射方法的方法句柄
      抛出:
      IllegalAccessException - 如果访问检查失败,或者如果方法是 static ,或者如果设置了方法的变量 arity 修饰符位并且 asVarargsCollector 失败
      NullPointerException - 如果任何参数为空
    • unreflectConstructor

      public MethodHandle  unreflectConstructor(构造方法 <?> c) throws IllegalAccessException
      为反射的构造函数生成方法句柄。方法句柄的类型将是构造函数的类型,返回类型更改为声明类。方法句柄将执行newInstance 操作,在传递给方法句柄的参数上创建构造函数类的新实例。

      如果未设置构造函数的accessible 标志,则立即代表查找类执行访问检查。

      当且仅当构造函数的可变元数修饰符位 (0x0080) 已设置时,返回的方法句柄将具有 变数

      如果返回的方法句柄被调用,构造方法的类将被初始化,如果它还没有被初始化的话。

      参数:
      c - 反射构造函数
      返回:
      可以调用反射构造方法的方法句柄
      抛出:
      IllegalAccessException - 如果访问检查失败或者如果设置了方法的变量 arity 修饰符位并且 asVarargsCollector 失败
      NullPointerException - 如果参数为空
    • unreflectGetter

      public MethodHandle  unreflectGetter(Field  f) throws IllegalAccessException
      生成一个方法句柄,提供对反射字段的读取访问权限。方法句柄的类型将具有字段值类型的返回类型。如果该字段是 static ,则方法句柄将不带任何参数。否则,它的单个参数将是包含该字段的实例。如果未设置 Field 对象的 accessible 标志,则代表查找类立即执行访问检查。

      如果该字段是静态的,并且调用了返回的方法句柄,则该字段的类将被初始化(如果尚未初始化)。

      参数:
      f - 反射场
      返回:
      可以从反射字段加载值的方法句柄
      抛出:
      IllegalAccessException - 如果访问检查失败
      NullPointerException - 如果参数为空
    • unreflectSetter

      public MethodHandle  unreflectSetter(Field  f) throws IllegalAccessException
      生成一个方法句柄,提供对反射字段的写访问权限。方法句柄的类型将具有 void 返回类型。如果字段是 static ,方法句柄将采用字段值类型的单个参数,即要存储的值。否则,这两个参数将是包含字段的实例和要存储的值。如果未设置 Field 对象的 accessible 标志,则代表查找类立即执行访问检查。

      如果该字段是 final ,将不允许写访问并且访问检查将失败,除非在为 Field.set 记录的某些狭窄情况下。仅当对 Field 对象的 set 方法的相应调用可以正常返回时,才会返回方法句柄。特别是,同时为 staticfinal 的字段可能永远不会被设置。

      如果该字段是 static ,并且调用了返回的方法句柄,则该字段的类将被初始化(如果尚未初始化)。

      参数:
      f - 反射场
      返回:
      可以将值存储到反射字段中的方法句柄
      抛出:
      IllegalAccessException - 如果访问检查失败,或者如果字段为 final 并且未在 Field 对象上启用写访问
      NullPointerException - 如果参数为空
    • unreflectVarHandle

      public VarHandle  unreflectVarHandle(Field  f) throws IllegalAccessException
      生成一个 VarHandle,可以访问类型为 R 的类中声明的类型为 T 的反射字段 f。 VarHandle 的变量类型是 T 。如果该字段是非静态的,则 VarHandle 具有一种坐标类型 R 。否则,该字段是静态的,并且 VarHandle 没有坐标类型。

      代表查找类立即执行访问检查,而不管字段的 accessible 标志的值如何。

      如果该字段是静态的,并且如果返回的 VarHandle 被操作,则该字段的声明类将被初始化(如果它尚未初始化)。

      在以下情况下,不支持返回的 VarHandle 的某些访问模式:

      • 如果该字段声明为 final ,则不支持写入、原子更新、数字原子更新和按位原子更新访问模式。
      • 如果字段类型不是 byteshortcharintlongfloatdouble,则不支持数字原子更新访问模式。
      • 如果字段类型不是 booleanbyteshortcharintlong,则不支持按位原子更新访问模式。

      如果该字段声明为 volatile,则返回的 VarHandle 将根据其指定的访问模式覆盖对该字段的访问(有效地忽略 volatile 声明)。

      如果字段类型是 floatdouble,则数字和原子更新访问模式使用它们的按位表示比较值(分别参见 Float.floatToRawIntBits(float) Double.doubleToRawLongBits(double) )。

      API 注意:
      float 值或 double 值的按位比较,由数字和原子更新访问模式执行,不同于原始 == 运算符以及 Float.equals(java.lang.Object) Double.equals(java.lang.Object) 方法,特别是比较 NaN 值或比较 -0.0+0.0 。在使用此类值执行比较和设置或比较和交换操作时应小心,因为操作可能会意外失败。有许多可能的 NaN 值在 Java 中被认为是 NaN,尽管 Java 提供的 IEEE 754 浮点运算无法区分它们。如果预期或见证值是 NaN 值并且它被转换(可能以特定于平台的方式)为另一个 NaN 值,并且因此具有不同的按位表示(请参阅 Float.intBitsToFloat(int) Double.longBitsToDouble(long) 了解更多详细信息),则可能会发生操作失败。值 -0.0+0.0 具有不同的按位表示,但在使用原始 == 运算符时被视为相等。例如,如果数字算法计算的预期值为 -0.0 并且先前计算的见证值为 +0.0 ,则可能会发生操作失败。
      参数:
      f - 反射字段,具有 T 类型的字段和 R 类型的声明类
      返回:
      允许访问非静态字段或静态字段的 VarHandle
      抛出:
      IllegalAccessException - 如果访问检查失败
      NullPointerException - 如果参数为空
      自从:
      9
    • revealDirect

      public MethodHandleInfo  revealDirect(MethodHandle  target)
      破解由此查找对象或类似对象创建的 直接方法句柄。执行安全和访问检查以确保此查找对象能够再现目标方法句柄。这意味着如果目标是直接方法句柄但是由不相关的查找对象创建的,则破解可能会失败。如果方法句柄是 来电敏感 并且是由不同类的查找对象创建的,就会发生这种情况。
      参数:
      target - 破解符号引用组件的直接方法句柄
      返回:
      一个符号引用,可用于从此查找对象重建此方法句柄
      抛出:
      SecurityException - 如果存在安全管理器并且它 拒绝访问
      IllegalArgumentException - 如果目标不是直接方法句柄或者访问检查失败
      NullPointerException - 如果目标是 null
      自从:
      1.8
      参见:
    • hasPrivateAccess

      @Deprecated (since ="14") public boolean hasPrivateAccess()
      已弃用。
      此方法最初旨在测试 PRIVATE 访问,这意味着完全权限访问,但 MODULE 访问已独立于 PRIVATE 访问。建议改为调用 hasFullPrivilegeAccess()
      如果此查找具有 PRIVATEMODULE 访问权限,则返回 true
      返回:
      true 如果此查找具有 PRIVATEMODULE 访问权限。
      自从:
      9
    • hasFullPrivilegeAccess

      public boolean hasFullPrivilegeAccess()
      如果此查找具有 full privilege access,即 PRIVATEMODULE 访问权限,则返回 trueLookup 对象必须具有完全权限访问权限才能访问允许访问 查找类 的所有成员。
      返回:
      true 如果此查找具有完全权限访问。
      自从:
      14
      参见: