In this blog we will discuss about a new feature which is being introduced in Java 11 Nested Based Access Control. Oracle introduces JVM level support for private access of nested classes, fields etc.
Nested Based Access Control
When we have nested classes in a class, after compilation different files are created. Before Java 11 for accessing the private member of the nested class or outer class we need to use the synthetic generated accessibility-broadening bridge methods.
But in Java 11 for accessing Classes and Interfaces Oracle has introduced another access control context known as nest.
Basically, the nest term defines a new access control context that allows classes that are logically part of the same code entity, but which are compiled with distinct class files, to access each other’s private members without the need for compilers to insert accessibility-broadening bridge methods (Java documentation).
So by the above defination we can say that this is a Java class bytecode level change.
Lets take an example
public class Test {
private static int x = 5;
public static class NestedTest {
public static void doSomething() {
System.out.println(x);
}
}
}
Now compile the code which will generate two classes
javac Test.java
- Test.class
- Test$NestedTest.class
Lets see what we have in these files Before Java 11
javap -v Test.class
static int access$000();
descriptor: ()I
flags: (0x1008) ACC_STATIC, ACC_SYNTHETIC
Code:
stack=1, locals=0, args_size=0
0: getstatic #1 // Field x:I
3: ireturn
LineNumberTable:
line 1: 0
javap -v 'Test$NestedTest.class'
public static void doSomething();
descriptor: ()V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=0, args_size=0
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: invokestatic #3 // Method Test.access$000:()I
6: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
9: return
LineNumberTable:
line 6: 0
line 7: 9
Here we can see when we want to access the private field x from the NestedTest.doSomething() a bridge package-private method access$000() is syntactically generated. This is just because after compilation two different compiles files are generated one for outer class and one for inner class. So to access each others private members we need some access control mechanism.
Java 11 introduced JVM level support for private access classes using two new terms “NestMembers” and “NestHost”.”NestMembers” corresponds to nested classes and “NestHost” corresponds to the enclosing outer class. From Java 11 onwards we use these terms for bridging to use the private member of a class as well.
Lets see what we have in these files After Java 11
javap -v Test.class
SourceFile: "Test.java"
NestMembers:
Test$NestedTest
InnerClasses:
public static #6= #5 of #3; // NestedTest=class Test$NestedTest of class Test
javap -v 'Test$NestedTest.class'
SourceFile: "Test.java"
NestHost: class Test
InnerClasses:
public static #23= #5 of #15; // NestedTest=class Test$NestedTest of class Test
Here we can see that in the compiled file we have NestHost and NestMembers which helped us to access the private members as it does not effect the end user but helps at a JVM level.
Hope this blog will help you.
Happy Coding !!!
References:-
