java11新特性---Nest-Based Access Control(嵌套访问控制)

简介

嵌套是一种访问控制上下文,它容许多个class同属一个逻辑代码块,可是被编译成多个分散的class文件,它们访问彼此的私有成员无需经过编译器添加访问扩展方法。java

动机

不少jvm语言支持在一个源文件中放多个class。这对于用户是透明的,用户认为它们在一个class中,因此但愿它们共享同一套访问控制体系。为了达到目的,编译器须要常常须要经过附加的access bridge扩大private成员的访问权限到package。这种bridge和封装相违背,而且轻微的增长程序的大小,会干扰用户和工具。因此咱们但愿一种更直接,更安全,更透明的方式。安全

一个更大的坑就是反射的时候会有问题。当使用java.lang.reflect.Method.invoke从一个nestmate调用另外一个nestmate私有方法时会报IllegalAccessError错误。这个是让人不能理解的,由于反射应该和源码级访问拥有相同权限。jvm

话很少说,看段代码
工具


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");
           //这里在java8环境下会报错,在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。spa

你们能够看一下上述代码的class文件详情。翻译

JVM针对嵌套成员的访问控制

调整了jvm访问规则,增长了以下条款:
一个field或method R能够被class或interface D访问,当且仅当以下任一条件为真:code

  • … …(原条款不变)
  • R是私有的,而且声明在另外一个class或interface C中,而且C和D是nestmates

C和D是nestmates表名他们确定有一个相同的hostci

这个松散的访问规则会做用在以下几个地方:(这一段我就贴原文了,感受翻译过来味道就变了)get

  • 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属性

相关文章
相关标签/搜索