When to initialize the method's class for MethodHandles.Lookup.findStatic()?

David Holmes david.holmes at oracle.com
Thu Mar 17 23:46:20 UTC 2022


Run with -Xlog:class+init=info to see the classes that get initialized 
and in what order.

David

On 18/03/2022 5:53 am, Raffaello Giulietti wrote:
> Hi again,
> 
> here's code that shows that initialization doesn't happen during lookup 
> but only upon invoking the method handle. (I'm on Java 17.)
> 
> As long as the 2nd line in main() is commented, you don't see the 
> message "Test_2 initialized", which shows that the lookup doesn't 
> initialize Test_2.
> When you uncomment the line in main(), the message will appear.
> 
> So, as advertised, it's the invocation of the method handle that can 
> trigger initialization, not the lookup.
> 
> 
> HTH
> Raffaello
> 
> ----
> 
> import java.lang.invoke.*;
> 
> public class Test_1 {
> 
>      static MethodHandle mh;
> 
>      static {
>          try {
>              mh = MethodHandles.lookup().findStatic(Test_2.class, 
> "testMethod", MethodType.methodType(int.class, int.class));
>          } catch (NoSuchMethodException | IllegalAccessException e) {
>              e.printStackTrace();
>          }
>      }
> 
>      public static void main(String[] args) throws Throwable {
>          System.out.println(mh);
>          // System.out.println(Test_1.mh.invoke(0));
>      }
> 
> }
> 
> 
> 
> 
> public class Test_2 {
> 
>      static {
>          System.out.println("Test_2 initialized");
>      }
> 
>      static int testMethod(int value) { return (value + 1); }
> 
> }
> 
> 
> 
> 
> On 2022-03-17 20:38, Raffaello Giulietti wrote:
>> Hi,
>>
>> as far as I can see, the code should not even compile, as there's a 
>> static field in Test_1 which is initialized with an expression that 
>> throws checked exceptions (findStatic(..)).
>>
>> In addition, it seems to me that there's nothing in your code that 
>> reveals whether Test_2 has been initialized during the lookup. How can 
>> you tell?
>>
>> Finally, the method handle invocation in Test_1 will throw, as you 
>> don't pass any argument to a handle that expects one.
>>
>> Can you perhaps add more details?
>>
>>
>> Greetings
>> Raffaello
>>
>>
>>
>> On 2022-03-17 17:42, Cheng Jin wrote:
>>> Hi there,
>>>
>>> The document of 
>>> https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html#findStatic(java.lang.Class,java.lang.String,java.lang.invoke.MethodType) 
>>> in the Java API is ambiguous in terms of when to initialize the 
>>> method's class as follows (the same description as in other OpenJDK 
>>> versions)
>>>
>>> If the returned method handle is invoked, the method's class will be 
>>> initialized, if it has not already been initialized.
>>>
>>>
>>> It occurs to me that the method's class should be initialized when 
>>> invoking the method handle but OpenJDK actually chooses to do the 
>>> initialization in lookup.findStatic() rather than in mh.invoke()
>>> e.g.
>>> import java.lang.invoke.*;
>>>
>>> public class Test_1 {
>>>      static MethodHandle mh = 
>>> MethodHandles.lookup().findStatic(Test_2.class, "testMethod", 
>>> MethodType.methodType(int.class, int.class)); <----------- 
>>> Test_2.class gets initialized and verified.
>>>
>>>      public static void main(String[] args) throws Throwable {
>>>          Test_1.mh.invoke();
>>>      }
>>> }
>>>
>>> public class Test_2 {
>>>      static int testMethod(int value) { return (value + 1); }
>>> }
>>>
>>> So there should be more clear explanation what is the correct or 
>>> expected behaviour at this point and why OpenJDK doesn't comply with 
>>> the document to delay the initialization of the method's class to 
>>> mh.invoke().
>>>
>>> Best Regards
>>> Cheng Jin


More information about the core-libs-dev mailing list