Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
301 views
in Technique[技术] by (71.8m points)

java - How Memory assigns to lambda | How does it refered,by non super class reference variable

I was creating the implementation of a functional interface, below is my code:

Consumer<Integer> consumer = new Consumer<Integer>() {
    @Override
    public void accept(Integer t) {
        System.out.println(t);
    }
};

As per the Java Documentation (javadoc)

A variable of a class type T can hold a null reference or a reference to an instance of class T or of any class that is a subclass of T.

In the code above, the anonymous object is created, which is a subclass of Consumer, and can be referred to by reference variable consumer, which is fine.

But I saw Consumer is a FunctionalInterface, so I can also do something like this in Java 8:

Using Lambda

Consumer<Integer> consumer = t -> System.out.println(t);

OR Using Method Reference

Consumer<Integer> consumer = System.out::println;

From what I know, no sub classes or anonymous classes are being created in both of the above cases. This result leaves me with two confusions:

1 : In the result of the lambda test, the variable consumer is not referring to subclass or Anonymous class of Consumer, so isn't this violating the above mentioned concept variable which can only refer child/self or null?

2 : How is memory assigned to lambdas, and how does the JVM handle such at run time?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

First of all Jean-Baptiste has shown you why the assignment works in the first place.

Now the part that I think that you are missing is the fact that the generated class of Consumer in case of Consumer<Integer> consumer = t -> System.out.println(t); is only visible at runtime due to invokedynamic.

Run your class with a flag :

java -Djdk.internal.lambda.dumpProxyClasses=/Your/Path

And you will notice that there is a generated class (inside a path of folders from your package name of the class) that contains a .class file sort of like this SOQuestion$$Lambda$1.class.

If you decompile that you will see that it's actually a class that implements Consumer:

final class org.eugene.so.SOQuestion$$Lambda$1 
            implements java.util.function.Consumer {
     public void accept(java.lang.Object);
}

If you look at the generated byte code where your lambda is defined, you will see that the lambda expression is actually de-sugared to a static method (for non-captureting lambdas, it could also be non-static if it is a capturing lambda). The code for it:

private static void lambda$main$0(java.lang.Integer);
Code:
   0: getstatic     #3  // Field java/lang/System.out:Ljava/io/PrintStream;
   3: aload_0
   4: invokevirtual #4  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   7: return

As far as how the VM manages memory for it, for an non-capturing lambda you will get a singleton, for a capturing-lambda you will get a new instance of each call. The absolute must read is here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...