模块  java.base
软件包  java.lang.invoke

Class MethodHandles.Lookup

  • Enclosing class:
    MethodHandles

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

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

    查找工厂方法

    Lookup对象上的工厂方法对应于方法,构造函数和字段的所有主要用例。 工厂方法创建的每个方法句柄都是特定字节码行为的功能等价物。 (字节码行为在Java虚拟机规范的5.4.3.5节中描述。)以下是这些工厂方法与生成的方法句柄行为之间的对应关系的摘要: lookup method behaviors lookup expression member bytecode behavior lookup.findGetter(C.class,"f",FT.class) FT f; (T) this.f; lookup.findStaticGetter(C.class,"f",FT.class) static
    FT f; (T) 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.unreflect(aMethod) (static)?
    T m(A*); (T) aMethod.invoke(thisOrNull, 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 名称aMethodaField ,和aConstructor代表对应于给定构件反射的对象。

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

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

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

    • 如果C无法从查找类的加载器以符号形式访问,则查找仍然可以成功,即使没有等效的Java表达式或字节编码常量也是如此。
    • 同样,如果TMT无法从查找类的加载器以符号方式访问,则查找仍然可以成功。 例如,无论请求的类型如何,查找MethodHandle.invokeExactMethodHandle.invoke将始终成功。
    • 如果安装了安全管理器,则可以基于各种理由禁止查找( see below )。 相反, CONSTANT_MethodHandle常量上的ldc指令不受安全管理器检查的约束。
    • 如果查找方法具有very large arity ,则方法句柄创建可能会失败,因为方法句柄类型具有太多参数。

    访问检查

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

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

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

    查找可能会失败,因为查找类无法访问包含类,或者因为缺少所需的类成员,或者因为查找类无法访问所需的类成员,或者因为查找对象不够信任访问该成员。 在任何这些情况下,将尝试查找抛出ReflectiveOperationException 确切的类将是以下之一:

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

    通常,可以为方法M查找方法句柄的条件不比查找类可以编译,验证和解析对M的调用的条件更具限制性。 在JVM引发异常(如NoSuchMethodError ,方法句柄查找通常会引发相应的已检查异常,例如NoSuchMethodException 并调用从查询产生的方法处理的效果是exactly equivalent ,以执行编制,验证和解决呼叫M 字段和构造函数也是如此。

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

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

    JVM对invokespecial指令施加了类似的要求,即receiver参数必须与已解析的方法当前类匹配。 同样,通过将前导参数的类型缩小到结果方法句柄来强制执行此要求。 (请参阅Java虚拟机规范,第4.10.1.9节。)

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

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

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

    关于 私人访问的 讨论:如果查询包含访问private成员(包括巢友的私人成员)的可能性,我们说查找具有私人访问权限 如其他地方的相关方法所述,只有具有私有访问权限的查找才具有以下功能:

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

    安全管理器交互

    尽管字节码指令只能引用相关类加载器中的类,但只要对其对象的引用可用,此API就可以在任何类中搜索方法。 使用Core Reflection API也可以使用这种交叉加载器引用,并且不可能对诸如invokestaticgetfield指令进行字节getfield 有一个security manager API允许应用程序检查此类交叉加载器引用。 这些检查适用于MethodHandles.Lookup API和Core Reflection API(如中所示 )。

    如果存在安全管理器,则成员和类查找将受到额外检查。 从一到三次调用安全管理器。 任何这些调用都可以通过抛出SecurityException来拒绝访问。 smgr定义为安全管理器,将lookc定义为当前查找对象的查找类,将refc为要在其中查找成员的包含类,将defc定义为实际定义该成员的类。 (如果一个类或其他类型的被存取时, refcdefc值是类本身。)的值lookc被定义为不存在 ,如果当前查找对象不具有private access 呼叫根据以下规则进行:

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

    来电者敏感的方法

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

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

    如果查找对象是publicLookup() ,或者没有private access的其他查找对象,则忽略查找类。 在这种情况下,不能创建调用者敏感的方法句柄,禁止访问,并且查找失败,并显示IllegalAccessException

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

    如果应用程序缓存方法句柄以进行广泛共享,则应使用publicLookup()来创建它们。 如果查找Class.forName ,它将失败,并且应用程序必须采取适当的操作。 可能是稍后的查找(可能在调用引导方法期间)可以包含调用者的特定标识,从而使该方法可访问。

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

    • 字段详细信息

      • PUBLIC

        public static final int PUBLIC
        表示public访问的单位掩码,可能导致lookupModes的结果。 0x01恰好与public modifier bit的值相同。
        另请参见:
        常数字段值
      • PRIVATE

        public static final int PRIVATE
        代表private访问的单位掩码,可能导致lookupModes的结果。 0x02恰好与private modifier bit的值相同。
        另请参见:
        常数字段值
      • PROTECTED

        public static final int PROTECTED
        表示protected访问的单位掩码,可能有助于lookupModes的结果。 0x04恰好与protected modifier bit的值相同。
        另请参见:
        常数字段值
      • PACKAGE

        public static final int PACKAGE
        表示package访问(默认访问)的单位掩码,可能会导致lookupModes的结果。 值为0x08 ,与任何特定的modifier bit无意义地对应。
        另请参见:
        常数字段值
      • 模块

        public static final int MODULE
        表示模块访问(默认访问)的单位掩码,可能会导致lookupModes的结果。 值为0x10 ,与任何特定的modifier bit无意义地对应。 PUBLIC修饰符位一起使用具有此查找模式的Lookup可以访问查找类模块中的所有公共类型以及其他模块导出到查找类模块的包中的公共类型。
        从以下版本开始:
        9
        另请参见:
        常数字段值
      • UNCONDITIONAL

        public static final int UNCONDITIONAL
        表示unconditional访问权限的单位掩码,可能导致lookupModes的结果。 值为0x20 ,与任何特定的modifier bit无意义地对应。 一个Lookup这种查找模式取得readability PUBLIC修饰符位一起使用具有此查找模式的Lookup可以访问所有模块的公共类型的所有公共成员,其中类型位于包exported unconditionally
        从以下版本开始:
        9
        另请参见:
        MethodHandles.publicLookup()常数字段值
    • 方法详细信息

      • lookupClass

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

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

        结果
        查找类,代表该查找对象查找成员
      • in

        public MethodHandles.Lookup in​(<?> requestedLookupClass)
        在指定的新查找类上创建查找。 生成的对象将报告指定的类为其自己的lookupClass

        但是,保证生成的Lookup对象不再具有Lookup对象的访问权限。 特别是,访问功能可能会丢失如下:

        • 如果旧查找类位于named模块中,并且新查找类位于不同的模块M ,则无法访问成员,甚至M的导出包中的公共成员。 例外情况是此查找为publicLookup ,在这种情况下, PUBLIC访问不会丢失。
        • 如果旧的查找类位于未命名的模块中,并且新的查找类是不同的模块,则会丢失模块访问权限。
        • 如果新查找类与旧查找类不同,则丢失UNCONDITIONAL
        • 如果新查找类与旧查找类不同,则无法访问受保护和默认(包)成员。
        • 如果新查找类与旧查找类不在同一个包成员中,则不能访问私有成员,并且凭借继承将无法访问受保护的成员。 (由于包共享,受保护的成员可能继续可访问。)
        • 如果旧查找类无法访问新的查找类,则无法访问任何成员,甚至是公共成员。 (在所有其他情况下,公共成员将继续可访问。)

        生成的查找加载类的功能(在findClass(java.lang.String)调用期间使用)由查找类'加载程序确定,加载程序可能会因此操作而更改。

        参数
        requestedLookupClass - 新查找对象的所需查找类
        结果
        报告所需查找类的查找对象,如果没有更改则报告相同的对象
        异常
        NullPointerException - 如果参数为null
      • dropLookupMode

        public MethodHandles.Lookup dropLookupMode​(int modeToDrop)
        在查找对象找到成员的同一查找类上创建查找,但查找模式已丢失给定的查找模式。 查找模式下降是一个PUBLIC模块PACKAGEPROTECTEDPRIVATE PROTECTEDUNCONDITIONAL始终被删除,因此生成的查找模式将永远不会具有这些访问功能。 删除PACKAGE ,生成的查找将不具有PACKAGEPRIVATE访问权限。 当拖放模块然后将得到的查找不会有模块PACKAGE ,或PRIVATE访问。 如果PUBLIC ,则生成的查找无权访问。
        参数
        modeToDrop - 要删除的查找模式
        结果
        缺少指示模式的查找对象,如果没有更改,则返回相同的对象
        异常
        IllegalArgumentException -如果 modeToDrop不是一个 PUBLIC模块PACKAGEPROTECTEDPRIVATEUNCONDITIONAL
        从以下版本开始:
        9
        另请参见:
        MethodHandles.privateLookupIn(java.lang.Class<?>, java.lang.invoke.MethodHandles.Lookup)
      • toString

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

        (受保护的访问应该比私有访问更强大可能看起来很奇怪。独立于包访问,受保护的访问首先被丢失,因为它需要调用者和被调用者之间的直接子类关系。)

        重写:
        toString在类 Object
        结果
        对象的字符串表示形式。
        另请参见:
        in(java.lang.Class<?>)
      • findStatic

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

        当且仅当设置了方法的变量arity修饰符位( 0x0080 )时,返回的方法句柄才会有variable arity

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

        例:

        
        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 - 如果存在安全管理器且 refuses access
        NullPointerException - 如果任何参数为null
      • findVirtual

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

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

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

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

        因为一般equivalence之间invokevirtual的指令和方法所生产手柄findVirtual ,如果类是MethodHandle和名称的字符串是invokeExactinvoke ,所得方法手柄等效于一个由产生MethodHandles.exactInvokerMethodHandles.invoker具有相同type参数。

        如果类为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 - 方法的类型,省略receiver参数
        结果
        所需的方法句柄
        异常
        NoSuchMethodException - 如果该方法不存在
        IllegalAccessException - 如果访问检查失败,或者方法是 static ,或者方法的变量arity修饰符位已设置且 asVarargsCollector失败
        SecurityException - 如果存在安全管理器且 refuses access
        NullPointerException - 如果任何参数为null
      • findConstructor

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

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

        当且仅当构造函数的变量arity修饰符位( 0x0080 )已设置时,返回的方法句柄才会有variable arity

        如果调用返回的方法句柄,则初始化构造函数的类(如果尚未初始化)。

        例:

        
        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 - 方法的类型,省略了receiver参数,以及void返回类型
        结果
        所需的方法句柄
        异常
        NoSuchMethodException - 如果构造函数不存在
        IllegalAccessException - 如果访问检查失败或者方法的变量arity修饰符位已设置且 asVarargsCollector失败
        SecurityException - 如果存在安全管理器且 refuses access
        NullPointerException - 如果任何参数为null
      • accessClass

        public <?> accessClass​(<?> targetClass)
                             throws IllegalAccessException
        确定是否可以从此Lookup对象定义的查找上下文中访问类。 该类的静态初始值设定项未运行。

        此处的查找上下文由lookup classlookup modes确定。

        参数
        targetClass - 要访问检查的类
        结果
        已访问检查的类
        异常
        IllegalAccessException - 如果无法使用允许的访问模式从查找类访问该类。
        SecurityException - 如果存在安全管理器且 refuses access
        从以下版本开始:
        9
      • findSpecial

        public MethodHandle findSpecial​(<?> refc,
                                        String name,
                                        MethodType type,
                                        <?> specialCaller)
                                 throws NoSuchMethodException,
                                        IllegalAccessException
        为虚方法生成早期绑定方法句柄。 它会绕过检查重写在接收机,方法as if calledinvokespecial从明确内指令指定specialCaller 方法句柄的类型将是方法的类型,具有适当受限的接收器类型。 (接收器类型将为specialCaller或子类型。)查找对象必须可以访问该方法及其所有参数类型。

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

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

        (注意:此API不显示名为"<init>" JVM内部方法,即使invokespecial指令在特殊情况下可以引用它们。使用findConstructor以安全的方式访问实例初始化方法。)

        例:

        
        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 - 方法的类型,省略receiver参数
        specialCaller - 建议的调用类执行 invokespecial
        结果
        所需的方法句柄
        异常
        NoSuchMethodException - 如果该方法不存在
        IllegalAccessException - 如果访问检查失败,或者方法是 static ,或者方法的变量arity修饰符位已设置且 asVarargsCollector失败
        SecurityException - 如果存在安全管理器且 refuses access
        NullPointerException - 如果任何参数为null
      • findVarHandle

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

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

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

        • 如果声明字段为final ,则不支持写入,原子更新,数字原子更新和按位原子更新访问模式。
        • 如果字段的类型是比其他任何byteshortcharintlongfloat ,或double然后数字原子更新的接入方式是不受支持的。
        • 如果字段的类型是比其他任何booleanbyteshortcharintlong然后按位原子更新的接入方式是不受支持的。

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

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

        API Note:
        由数值和原子更新访问模式执行的float值或double值的按位比较不同于原始==运算符和Float.equals(java.lang.Object)Double.equals(java.lang.Object)方法,特别是关于比较NaN值或比较-0.0+0.0 由于操作可能意外失败,因此在执行比较和设置或比较和交换操作时应小心这些值。 Java中有许多可能的NaN值被认为是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 - 如果存在安全管理器且 refuses access
        NullPointerException - 如果任何参数为null
        从以下版本开始:
        9
      • findStaticGetter

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

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

        参数
        refc - 从中访问方法的类或接口
        name - 该字段的名称
        type - 字段的类型
        结果
        一个方法句柄,可以从字段加载值
        异常
        NoSuchFieldException - 如果该字段不存在
        IllegalAccessException - 如果访问检查失败,或者该字段不是 static
        SecurityException - 如果存在安全管理器且 refuses access
        NullPointerException - 如果任何参数为null
      • findStaticSetter

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

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

        参数
        refc - 从中访问方法的类或接口
        name - 该字段的名称
        type - 字段的类型
        结果
        一个方法句柄,可以将值存储到字段中
        异常
        NoSuchFieldException - 如果该字段不存在
        IllegalAccessException - 如果访问检查失败,或者该字段不是 static
        SecurityException - 如果存在安全管理器且 refuses access
        NullPointerException - 如果任何参数为null
      • findStaticVarHandle

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

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

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

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

        • 如果该字段声明为final ,则不支持写入,原子更新,数字原子更新和按位原子更新访问模式。
        • 如果字段的类型是比其他任何byteshortcharintlongfloat ,或double ,然后数字原子更新的接入方式是不受支持的。
        • 如果字段的类型是比其他任何booleanbyteshortcharintlong然后按位原子更新的接入方式是不受支持的。

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

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

        API Note:
        由数值和原子更新访问模式执行的float值或double值的按位比较与原始==运算符和Float.equals(java.lang.Object)Double.equals(java.lang.Object)方法不同,特别是在比较NaN值或比较-0.0+0.0 由于操作可能意外失败,因此在执行比较和设置或比较和交换操作时应小心这些值。 Java中有许多可能的NaN值被认为是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 - 如果存在安全管理器且 refuses access
        NullPointerException - 如果任何参数为null
        从以下版本开始:
        9
      • bind

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

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

        这几乎等同于以下代码,下面提到了一些差异:

        
        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()receiver.getClass()的超类型,其中查找类可以访问所请求的方法。 (与bind不同, bindTo不保留变量arity。另外, bindTo可能会抛出ClassCastException ,其中bind会抛出IllegalAccessException ,如成员为protected并且接收器被findVirtual限制为查找类。)
        参数
        receiver - 从中访问方法的对象
        name - 方法的名称
        type - 方法的类型,省略receiver参数
        结果
        所需的方法句柄
        异常
        NoSuchMethodException - 如果该方法不存在
        IllegalAccessException - 如果访问检查失败或者方法的变量arity修饰符位已设置且 asVarargsCollector失败
        SecurityException - 如果存在安全管理器且 refuses access
        NullPointerException - 如果任何参数为null
        另请参见:
        MethodHandle.bindTo(java.lang.Object)findVirtual(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType)
      • unreflect

        public MethodHandle unreflect​(方法 m)
                               throws IllegalAccessException
        如果查找类具有权限,则将direct method handle设置m 如果m是非静态的,则将receiver参数视为初始参数。 如果m是虚拟的,则在每次调用时都会遵守覆盖。 与Core Reflection API不同, 包含异常。 方法句柄的类型将是方法的类型,接收器类型前置(但仅当它是非静态的)。 如果未设置方法的accessible标志,则代表查找类立即执行访问检查。 如果m不公开,请不要与不受信任的方共享生成的句柄。

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

        如果m是静态的,并且如果调用返回的方法句柄,则初始化方法的类(如果尚未初始化)。

        参数
        m - 反映的方法
        结果
        一个方法句柄,可以调用反射的方法
        异常
        IllegalAccessException - 如果访问检查失败或者方法的变量arity修饰符位已设置且 asVarargsCollector失败
        NullPointerException - 如果参数为null
      • unreflectSpecial

        public MethodHandle unreflectSpecial​(方法 m,
                                             <?> specialCaller)
                                      throws IllegalAccessException
        为反射方法生成方法句柄。 它会绕过检查重写在接收机,方法as if calledinvokespecial从明确内指令指定specialCaller 方法句柄的类型将是方法的类型,具有适当受限的接收器类型。 (接收器类型将为specialCaller或子类型。)如果未设置方法的accessible标志,则代表查找类立即执行访问检查,就像链接了invokespecial指令一样。

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

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

        参数
        m - 反映的方法
        specialCaller - 名义上调用该方法的类
        结果
        一个方法句柄,可以调用反射的方法
        异常
        IllegalAccessException - 如果访问检查失败,或者方法是 static ,或者方法的变量arity修饰符位已设置且 asVarargsCollector失败
        NullPointerException - 如果任何参数为null
      • unreflectConstructor

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

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

        当且仅当设置了构造函数的变量arity修饰符位( 0x0080 )时,返回的方法句柄才会有variable arity

        如果调用返回的方法句柄,则初始化构造函数的类(如果尚未初始化)。

        参数
        c - 反射的构造函数
        结果
        一个方法句柄,可以调用反射的构造函数
        异常
        IllegalAccessException - 如果访问检查失败或者方法的变量arity修饰符位已设置且 asVarargsCollector失败
        NullPointerException - 如果参数为null
      • unreflectGetter

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

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

        参数
        f - 反射场
        结果
        方法句柄,可以从反射字段加载值
        异常
        IllegalAccessException - 如果访问检查失败
        NullPointerException - 如果参数为null
      • unreflectSetter

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

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

        参数
        f - 反射场
        结果
        方法句柄,可以将值存储到反射字段中
        异常
        IllegalAccessException - 如果访问检查失败
        NullPointerException - 如果参数为null
      • unreflectVarHandle

        public VarHandle unreflectVarHandle​(字段 f)
                                     throws IllegalAccessException
        生成一个VarHandle,允许访问类型为T的一个f类型的反射字段R VarHandle的变量类型是T 如果该字段是非静态的,则VarHandle具有一个坐标类型, R 否则,该字段是静态的,VarHandle没有坐标类型。

        无论字段accessible标志的值如何,都会立即代表查找类执行访问检查。

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

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

        • 如果声明字段为final ,则不支持写入,原子更新,数字原子更新和按位原子更新访问模式。
        • 如果字段的类型是比其他任何byteshortcharintlongfloat ,或double然后数字原子更新的接入方式是不受支持的。
        • 如果字段的类型是比其他任何booleanbyteshortcharintlong然后按位原子更新的接入方式是不受支持的。

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

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

        API Note:
        由数值和原子更新访问模式执行的float值或double值的按位比较不同于原始==运算符和Float.equals(java.lang.Object)Double.equals(java.lang.Object)方法,特别是关于比较NaN值或将-0.0+0.0进行比较。 由于操作可能意外失败,因此在执行比较和设置或比较和交换操作时应小心这些值。 Java中有许多可能的NaN值被认为是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 - 如果参数为null
        从以下版本开始:
        9
      • revealDirect

        public MethodHandleInfo revealDirect​(MethodHandle target)
        破解由此查找对象或类似对象创建的direct method handle 执行安全性和访问检查以确保该查找对象能够再现目标方法句柄。 这意味着如果target是直接方法句柄但是由不相关的查找对象创建,则破解可能会失败。 如果方法句柄是caller sensitive并且由另一个类的查找对象创建,则会发生这种情况。
        参数
        target - 破解为符号引用组件的直接方法句柄
        结果
        一个符号引用,可用于从此查找对象重建此方法句柄
        异常
        SecurityException - 如果存在安全管理器且 refuses access
        IllegalArgumentException - 如果目标不是直接方法句柄或访问检查失败
        NullPointerException - 如果目标是 null
        从以下版本开始:
        1.8
        另请参见:
        MethodHandleInfo
      • hasPrivateAccess

        public boolean hasPrivateAccess()
        如果此查找具有 PRIVATE访问权限,则返回 true
        结果
        true如果此查找具有 PRIVATE访问权限。
        从以下版本开始:
        9