In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly shows you how to solve the problem of access control optimization based on nested relationship in Java11. The content is simple and clear. I hope it can help you solve your doubts. Let me take you to study and learn this article "how to solve the optimization problem of access control based on nested relationship in Java11".
The Java language is powerful, but where there are people, there are rivers and lakes, and where there are apes, there is the core code of bug,Java is not perfect. For example, there is also an anti-pattern implementation introduced in the anti-pattern interface constant in JDK, and the technical debt mentioned in this article: nested relationship (NestMate) invocation.
In the Java language, classes and interfaces can be nested with each other, and this combination can have unrestricted access to each other, including each other's constructors, fields, methods, and so on. Even if the private is private, it can access each other. For example, it is defined as follows:
Public class Outer {private int i; public void print1 () {print11 (); print12 ();} private void print11 () {System.out.println (I);} private void print12 () {System.out.println (I);} public void callInnerMethod () {final Inner inner = new Inner (); inner.print4 (); inner.print5 () System.out.println (inner.j);} public class Inner {private int j; public void print3 () {System.out.println (I); print1 ();} public void print4 () {System.out.println (I); print11 (); print12 () } private void print5 () {System.out.println (I); print11 (); print12 ();}
In the above example, the field I, methods print11 and print12 in the Outer class are private, but they can be accessed directly in the Inner class, while the field j and method print5 in the Inner class are private and can also be used in the Outer class. This design is for better encapsulation, from the user's point of view, these nested classes / interfaces are integrated, and the separate definition is to better encapsulate themselves and isolate different features, but because they are one with each other, so private elements should also be common.
The previous implementation of Java11
We compile using Java8, and then use the javap-c command to see the results of Outer and Inner, respectively.
$javap-c Outer.class Compiled from "Outer.java" public class cn.howardliu.tutorials.java8.nest.Outer {public cn.howardliu.tutorials.java8.nest.Outer (); Code: 0: aload_0 1: invokespecial # 4 / / Method java/lang/Object. ": () V 4: return public void print1 () Code: 0: aload_0 1: invokespecial # 2 / / Method print11: () V 4: aload_0 5: invokespecial # 1 / / Method print12: () V 8: return public void callInnerMethod () Code: 0: new # 7 / / class cn/howardliu/tutorials/java8/nest/Outer$Inner 3: dup 4: aload_0 5: invokespecial # 8 / / Method cn/howardliu/tutorials/java8/nest/Outer$Inner. "(Lcn/howardliu/tutorials/java8/nest/Outer ) V 8: astore_1 9: aload_1 10: invokevirtual # 9 / / Method cn/howardliu/tutorials/java8/nest/Outer$Inner.print4: () V 13: aload_1 14: invokestatic # 10 / / Method cn/howardliu/tutorials/java8/nest/Outer$Inner.access$000: (Lcn/howardliu/tutorials/java8/nest/Outer$Inner ) V 17: getstatic # 5 / / Field java/lang/System.out:Ljava/io/PrintStream; 20: aload_1 21: invokestatic # 11 / / Method cn/howardliu/tutorials/java8/nest/Outer$Inner.access$100: (Lcn/howardliu/tutorials/java8/nest/Outer$Inner ) I 24: invokevirtual # 6 / / Method java/io/PrintStream.println: (I) V 27: return static int access$200 (cn.howardliu.tutorials.java8.nest.Outer); Code: 0: aload_0 1: getfield # 3 / / Field iRanger I 4: ireturn static void access$300 (cn.howardliu.tutorials.java8.nest.Outer) Code: 0: aload_0 1: invokespecial # 2 / / Method print11: () V 4: return static void access$400 (cn.howardliu.tutorials.java8.nest.Outer); Code: 0: aload_0 1: invokespecial # 1 / / Method print12: () V 4: return}
Let's take a look at the compilation result of Inner. It is important to note that the inner class uses a special naming method to define the Inner class, and eventually stores the compilation result in two files:
$javap-c Outer\ $Inner.classCompiled from "Outer.java" public class cn.howardliu.tutorials.java8.nest.Outer$Inner {final cn.howardliu.tutorials.java8.nest.Outer this$0; public cn.howardliu.tutorials.java8.nest.Outer$Inner (cn.howardliu.tutorials.java8.nest.Outer); Code: 0: aload_0 1: aload_1 2: putfield # 3 / / Field this$0:Lcn/howardliu/tutorials/java8/nest/Outer 5: aload_0 6: invokespecial # 4 / / Method java/lang/Object. "": () V 9: return public void print3 (); Code: 0: getstatic # 5 / / Field java/lang/System.out:Ljava/io/PrintStream 3: aload_0 4: getfield # 3 / / Field this$0:Lcn/howardliu/tutorials/java8/nest/Outer; 7: invokestatic # 6 / / Method cn/howardliu/tutorials/java8/nest/Outer.access$200: (Lcn/howardliu/tutorials/java8/nest/Outer ) I 10: invokevirtual # 7 / / Method java/io/PrintStream.println: (I) V 13: aload_0 14: getfield # 3 / / Field this$0:Lcn/howardliu/tutorials/java8/nest/Outer; 17: invokevirtual # 8 / / Method cn/howardliu/tutorials/java8/nest/Outer.print1: () V 20: return public void print4 () Code: 0: getstatic # 5 / / Field java/lang/System.out:Ljava/io/PrintStream; 3: aload_0 4: getfield # 3 / / Field this$0:Lcn/howardliu/tutorials/java8/nest/Outer 7: invokestatic # 6 / / Method cn/howardliu/tutorials/java8/nest/Outer.access$200: (Lcn/howardliu/tutorials/java8/nest/Outer;) I 10: invokevirtual # 7 / / Method java/io/PrintStream.println: (I) V 13: aload_0 14: getfield # 3 / / Field this$0:Lcn/howardliu/tutorials/java8/nest/Outer 17: invokestatic # 9 / / Method cn/howardliu/tutorials/java8/nest/Outer.access$300: (Lcn/howardliu/tutorials/java8/nest/Outer;) V 20: aload_0 21: getfield # 3 / / Field this$0:Lcn/howardliu/tutorials/java8/nest/Outer 24: invokestatic # 10 / / Method cn/howardliu/tutorials/java8/nest/Outer.access$400: (Lcn/howardliu/tutorials/java8/nest/Outer;) V 27: return static void access$000 (cn.howardliu.tutorials.java8.nest.Outer$Inner); Code: 0: aload_0 1: invokespecial # 2 / / Method print5: () V 4: return static int access$100 (cn.howardliu.tutorials.java8.nest.Outer$Inner) Code: 0: aload_0 1: getfield # 1 / / Field j:I 4: ireturn}
We can see that there are several more methods in Outer and Inner, and the format of the method name is access$*00.
The access$200 method in Outer returns the properties iQuery accessory 300 and access$400 calls the print11 and print12 methods, respectively. These new methods are static, and the scope is the default scope, that is, available in the package. These methods are eventually called by print3 and print4 in the Inner class, which is equivalent to indirectly calling private properties or methods in Outer.
We call these generated methods "bridge" methods (Bridge Method), which are a way to access each other within nested relationships.
When compiling, Java compiles nested classes into multiple class files in order to maintain the single nature of the class, and automatically creates a "bridge" method that calls private methods in order to ensure that nested classes can access each other, so that the nested syntax is implemented while keeping the original definition unchanged.
Technical debt
The implementation of the "bridge" method is ingenious, but it can cause inconsistency between the source code and the access control permissions of the compilation result. For example, we can call private methods in Outer in Inner. According to reason, we can call Outer methods in Inner through reflection, but in practice, we can't, and we will throw an IllegalAccessException exception. Let's check it out:
Public class Outer {/ / omit other methods public void callInnerReflectionMethod () throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {final Inner inner = new Inner (); inner.callOuterPrivateMethod (this);} public class Inner {/ / omit other methods public void callOuterPrivateMethod (Outer outer) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {final Method method = outer.getClass (). GetDeclaredMethod ("print12") Method.invoke (outer);}
Define test cases:
@ Testvoid gotAnExceptionInJava8 () {final Outer outer = new Outer (); final Exception e = assertThrows (IllegalAccessException.class, outer::callInnerReflectionMethod); e.printStackTrace (); assertDoesNotThrow (outer::callInnerMethod);}
The printed exception message is:
Java.lang.IllegalAccessException: class cn.howardliu.tutorials.java8.nest.Outer$Inner cannot access a member of class cn.howardliu.tutorials.java8.nest.Outer with modifiers "private"
At java.base/jdk.internal.reflect.Reflection.newIllegalAccessException (Reflection.java:361)
At java.base/java.lang.reflect.AccessibleObject.checkAccess (AccessibleObject.java:591)
At java.base/java.lang.reflect.Method.invoke (Method.java:558)
At cn.howardliu.tutorials.java8.nest.Outer$Inner.callOuterPrivateMethod (Outer.java:62)
At cn.howardliu.tutorials.java8.nest.Outer.callInnerReflectionMethod (Outer.java:36)
Calling private methods directly through reflection will fail, but it is strange that these "bridge" methods can be accessed directly or through reflection. So put forward JEP181 improvement, repair this technical debt at the same time, pave the way for subsequent improvement.
Implementation in Java11
Let's take a look at the compiled result of Java11:
$javap-c Outer.class Compiled from "Outer.java" public class cn.howardliu.tutorials.java11.nest.Outer {public cn.howardliu.tutorials.java11.nest.Outer (); Code: 0: aload_0 1: invokespecial # 1 / / Method java/lang/Object. ": () V 4: return public void print1 () Code: 0: aload_0 1: invokevirtual # 2 / / Method print11: () V 4: aload_0 5: invokevirtual # 3 / / Method print12: () V 8: return public void callInnerMethod () Code: 0: new # 7 / / class cn/howardliu/tutorials/java11/nest/Outer$Inner 3: dup 4: aload_0 5: invokespecial # 8 / / Method cn/howardliu/tutorials/java11/nest/Outer$Inner. "(Lcn/howardliu/tutorials/java11/nest/Outer ) V 8: astore_1 9: aload_1 10: invokevirtual # 9 / / Method cn/howardliu/tutorials/java11/nest/Outer$Inner.print4: () V 13: aload_1 14: invokevirtual # 10 / / Method cn/howardliu/tutorials/java11/nest/Outer$Inner.print5: () V 17: getstatic # 4 / / Field java/lang/System.out:Ljava/io/PrintStream 20: aload_1 21: getfield # 11 / / Field cn/howardliu/tutorials/java11/nest/Outer$Inner.j:I 24: invokevirtual # 6 / / Method java/io/PrintStream.println: (I) V 27: return}
Whether it is clean or not is consistent with the source structure of the Outer class. Let's see if there are any changes in Inner:
$javap-c Outer\ $Inner.classCompiled from "Outer.java" public class cn.howardliu.tutorials.java11.nest.Outer$Inner {final cn.howardliu.tutorials.java11.nest.Outer this$0; public cn.howardliu.tutorials.java11.nest.Outer$Inner (cn.howardliu.tutorials.java11.nest.Outer); Code: 0: aload_0 1: aload_1 2: putfield # 1 / / Field this$0:Lcn/howardliu/tutorials/java11/nest/Outer 5: aload_0 6: invokespecial # 2 / / Method java/lang/Object. "": () V 9: return public void print3 (); Code: 0: getstatic # 3 / / Field java/lang/System.out:Ljava/io/PrintStream 3: aload_0 4: getfield # 1/ / Field this$0:Lcn/howardliu/tutorials/java11/nest/Outer 7: getfield # 4 / / Field cn/howardliu/tutorials/java11/nest/Outer.i:I 10: invokevirtual # 5 / / Method java/io/PrintStream.println: (I) V 13: aload_0 14: getfield # 1 / / Field this$0:Lcn/howardliu/tutorials/java11/nest/Outer 17: invokevirtual # 6 / / Method cn/howardliu/tutorials/java11/nest/Outer.print1: () V 20: return public void print4 (); Code: 0: getstatic # 3 / / Field java/lang/System.out:Ljava/io/PrintStream 3: aload_0 4: getfield # 1/ / Field this$0:Lcn/howardliu/tutorials/java11/nest/Outer 7: getfield # 4 / / Field cn/howardliu/tutorials/java11/nest/Outer.i:I 10: invokevirtual # 5 / / Method java/io/PrintStream.println: (I) V 13: aload_0 14: getfield # 1 / / Field this$0:Lcn/howardliu/tutorials/java11/nest/Outer 17: invokevirtual # 7 / / Method cn/howardliu/tutorials/java11/nest/Outer.print11: () V 20: aload_0 21: getfield # 1 / / Field this$0:Lcn/howardliu/tutorials/java11/nest/Outer; 24: invokevirtual # 8 / / Method cn/howardliu/tutorials/java11/nest/Outer.print12: () V 27: return}
Just as clean.
We are verifying the reflection call through the test case:
@ Testvoid doesNotGotAnExceptionInJava11 () {final Outer outer = new Outer (); assertDoesNotThrow (outer::callInnerReflectionMethod); assertDoesNotThrow (outer::callInnerMethod);}
The result is normal operation.
This is the expected result of JEP181, the source code is consistent with the compiled result, and the access control is consistent.
New API for Nestmate
Several new API have been added to Java11 for validating nested relationships:
GetNestHost
This method returns the nested host (NestHost), and turning to Mandarin is to find the outer class of the nested class. For non-nested classes, return directly to yourself (which is actually a return to the outer class).
Let's take a look at the usage:
@ Testvoid checkNestHostName () {final String outerNestHostName = Outer.class.getNestHost () .getName (); assertEquals ("cn.howardliu.tutorials.java11.nest.Outer", outerNestHostName); final String innerNestHostName = Inner.class.getNestHost () .getName (); assertEquals ("cn.howardliu.tutorials.java11.nest.Outer", innerNestHostName); assertEquals (outerNestHostName, innerNestHostName); final String notNestClass = NotNestClass.class.getNestHost () .getName () AssertEquals ("cn.howardliu.tutorials.java11.nest.NotNestClass", notNestClass);
Cn.howardliu.tutorials.java11.nest.Outer is returned for both Outer and Inner.
GetNestMembers
This method returns an array of nested members of the nested class, and the element with a subscript of 0 is determined to be the class corresponding to NestHost, and the order of the other elements is not given a collation. Let's take a look at the use:
@ Testvoid getNestMembers () {final List outerNestMembers = Arrays.stream (Outer.class.getNestMembers ()) .map (Class::getName) .targets (Collectors.toList ()); assertEquals (2, outerNestMembers.size ()); assertTrue (outerNestMembers.contains ("cn.howardliu.tutorials.java11.nest.Outer")); assertTrue (outerNestMembers.contains ("cn.howardliu.tutorials.java11.nest.Outer$Inner")) Final List innerNestMembers = Arrays.stream (Inner.class.getNestMembers ()) .map (Class::getName) .map (Collectors.toList ()); assertEquals (2, innerNestMembers.size ()); assertTrue (innerNestMembers.contains ("cn.howardliu.tutorials.java11.nest.Outer")); assertTrue (innerNestMembers.contains ("cn.howardliu.tutorials.java11.nest.Outer$Inner"));} isNestmateOf
This method is used to determine whether two classes are NestMate of each other, forming a nested relationship with each other. The judgment is still based on nested hosts, and as long as they are the same, the two are NestMate. Let's take a look at the use:
@ Testvoid checkIsNestmateOf () {assertTrue (Inner.class.isNestmateOf (Outer.class)); assertTrue (Outer.class.isNestmateOf (Inner.class));} subsequent improvements
Nested relationships are part of the Valhalla project, where one of the main goals is to improve value types and generics in JAVA. There will be more improvements later:
In generic specialization (generic specialization), each specialized type (specialized type) can be created as a generic Nestmate.
Support for secure replacement of Unsafe.defineAnonymousClass () API, implementing Nestmate that creates a new class as an existing class.
It may affect the "sealed class" (sealed classes), allowing only subclasses of Nestmate as sealed classes.
Private nested types may be affected. Private nested types are currently defined as in-package accessibility (package-access).
What are the collection classes in Java? the sets in Java are mainly divided into four categories: 1, List list: ordered, repeatable; 2, Queue queue: ordered, repeatable; 3, Set collection: non-repeatable; 4, Map mapping: disorder, key unique, value is not unique.
The above is about "how to solve the problem of access control optimization based on nested relationship in Java11". If this article is helpful to you and you think it is well written, please share it with your friends to learn new knowledge. if you want to know more about it, please pay more attention to the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.