4

I wrote simple example of using method reference:

public class Main {
private static String identity(String param) {
    return param;
}

public static void main(String... args) {
    Function<String, String> fun = Main::identity;
    System.out.println(fun.apply("Hello"));
}}

And in generated byte code is InnerClass:

InnerClasses:
 public static final #68= #67 of #71; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:
0: #35 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
  #36 (Ljava/lang/Object;)Ljava/lang/Object;....

I supposed this innerClass is used in lambda bootstrap method, but I do not know when jvm create object of this class and what information will be store in object of this class. Could anyone explain it to me?

Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93
lolcio
  • 346
  • 5
  • 12
  • No object is created because your method is `static`. I'm not sure I understand your question. – Boris the Spider Feb 03 '18 at 19:57
  • @BoristheSpider I think OP is talking about the `fun` object? – Jorn Vernee Feb 03 '18 at 19:58
  • I wondered what is this inner class and why compiler generated it. If I see "InnerClasses" in byte code I supposed that jvm eventually create object of this class. – lolcio Feb 03 '18 at 20:03
  • This might help: https://stackoverflow.com/questions/30002380/why-are-java-8-lambdas-invoked-using-invokedynamic. Lambdas can possibly be converted into anonymous classes that are a type of inner class: https://docs.oracle.com/javase/tutorial/java/javaOO/innerclasses.html. – tsolakp Feb 03 '18 at 22:53

1 Answers1

7

This is not a generated inner class, but rather InnerClasses attribute specified in JVMS §4.7.6. The specification requires that this attribute lists every class (referenced in the constant pool) that is not a member of a package.

Basically, javac generates InnerClasses attribute for all inner classes it sees in the code. E.g.

public class Test {
    public static void main(String[] args) {
        for (Map.Entry e : Collections.emptyMap().entrySet()) {

        }
    }
}

The bytecode for above class will refer to Map.Entry as an inner class of Map:

InnerClasses:
   public static #31= #7 of #23; //Entry=class java/util/Map$Entry of class java/util/Map

In JDK lambdas are implemented with invokedynamic instruction. According to the specification, resolution of invokedynamic involves calling a bootstrap method with 4 arguments of the following types:

  1. MethodHandle
  2. MethodHandles.Lookup
  3. String
  4. MethodType

Java Runtime creates these objects internally, but since the bytecode refers to MethodHandles.Lookup class, javac generates InnerClasses attribute for it.

apangin
  • 92,924
  • 10
  • 193
  • 247
  • That part of §4.7.6 annoys me for years now… Why does *every* class have to redundantly repeat the information about inner class relations of referenced classes. I can’t imagine any actual use case for that information, as no-one would consider consulting the byte code of `Test` to find out whether `Map.Entry` is a nested type. – Holger Feb 05 '18 at 16:52