内容简介:嵌套是一种访问控制上下文,它允许多个class同属一个逻辑代码块,但是被编译成多个分散的class文件,它们访问彼此的私有成员无需通过编译器添加访问扩展方法。很多jvm语言支持在一个源文件中放多个class。这对于用户是透明的,用户认为它们在一个class中,所以希望它们共享同一套访问控制体系。为了达到目的,编译器需要经常需要通过附加的access bridge扩大private成员的访问权限到package。这种bridge和封装相违背,并且轻微的增加程序的大小,会干扰用户和工具。所以我们希望一种更直接
简介
嵌套是一种访问控制上下文,它允许多个class同属一个逻辑代码块,但是被编译成多个分散的class文件,它们访问彼此的私有成员无需通过编译器添加访问扩展方法。
动机
很多jvm语言支持在一个源文件中放多个class。这对于用户是透明的,用户认为它们在一个class中,所以希望它们共享同一套访问控制体系。为了达到目的,编译器需要经常需要通过附加的access bridge扩大private成员的访问权限到package。这种bridge和封装相违背,并且轻微的增加程序的大小,会干扰用户和工具。所以我们希望一种更直接,更安全,更透明的方式。
一个更大的坑就是反射的时候会有问题。当使用java.lang.reflect.Method.invoke从一个nestmate调用另一个nestmate私有方法时会报IllegalAccessError错误。这个是让人不能理解的,因为反射应该和源码级访问拥有相同权限。
话不多说,看段代码
public class JEP181 { public static class Nest1 { private int varNest1; public void f() throws Exception { final Nest2 nest2 = new Nest2(); //这里没问题 nest2.varNest2 = 2; final Field f2 = Nest2.class.getDeclaredField("varNest2"); //这里在 java 8环境下会报错,在java11中是没问题的 f2.setInt(nest2, 2); System.out.println(nest2.varNest2); } } public static class Nest2 { private int varNest2; } public static void main(String[] args) throws Exception { new Nest1().f(); } } 复制代码
在java11之前,classfile用InnerClasses和EnclosingMethod两种属性来帮助编译器确认源码的嵌套关系,每一个嵌套的类型会编译到自己的class文件中,在使用上述属性来连接其他class文件。这些属性对于jvm确定嵌套关系上已经足够了,但是它们不直接适用于访问控制,并且和java语言绑定的太紧了。
为了提供一种更大的,更广泛的,不仅仅是java语言的嵌套类型,并且补足访问控制检测的不足,引入了两个新的class文件属性。定义了两种nest member,一种叫nest host(也叫top-level class),它包含一个NestMembers属性用于确定其他静态的nest members,其他的就是nest member,它包含一个NestHost属性用于确定它的nest host。
大家可以看一下上述代码的class文件详情。
JVM针对嵌套成员的访问控制
调整了jvm访问规则,增加了如下条款:
一个field或method R可以被class或interface D访问,当且仅当如下任一条件为真:
- … …(原条款不变)
- R是私有的,并且声明在另一个class或interface C中,并且C和D是nestmates
C和D是nestmates表名他们肯定有一个相同的host
这个松散的访问规则会作用在如下几个地方:(这一段我就贴原文了,感觉翻译过来味道就变了)
- Resolving fields and methods (JVMS 5.4.3.2, etc.)
- Resolving method handle constants (JVMS 5.4.3.5)
- Resolving call site specifiers (JVMS 5.4.3.6)
- Checking Java language access by instances of java.lang.reflect.AccessibleObject
- Checking access during queries to java.lang.invoke.MethodHandles.Lookup
针对上述访问规则的改变,相应的调整字节码:
- invokespecial for private nestmate constructors,
- invokevirtual for private non-interface, nestmate instance methods,
- invokeinterface for private interface, nestmate instance methods; and
- invokestatic for private nestmate, static methods
嵌套类的校验
嵌套类必须在访问前校验。校验最迟要发生在访问成员之前,最早可以发生在对class文件的校验时,或者在两者之间,比如JIT时。校验嵌套关系,需要加载nest host类,为了防止无意义的加载,这一步尽量放到最后做。
为了保证嵌套的完整性,建议禁止修改nest classfile属性
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Computers and Intractability
M R Garey、D S Johnson / W. H. Freeman / 1979-4-26 / GBP 53.99
This book's introduction features a humorous story of a man with a line of people behind him, who explains to his boss, "I can't find an efficient algorithm, but neither can all these famous people." ......一起来看看 《Computers and Intractability》 这本书的介绍吧!