Новая функция java11 --- Nest-Based Access Control (вложенный контроль доступа)

Java задняя часть JVM переводчик

Введение

Вложенность — это контекст управления доступом, который позволяет нескольким классам принадлежать одному и тому же логическому блоку кода, но компилируется в несколько отдельных файлов классов, которые обращаются к закрытым членам друг друга без добавления методов расширения доступа через компилятор.

мотивация

Многие языки JVM поддерживают несколько классов в исходном файле. Это прозрачно для пользователя, который думает, что находится в одном классе, поэтому хочет использовать одну и ту же систему управления доступом. Для этого компилятору часто требуется расширить права доступа закрытых членов к пакету через дополнительные мосты доступа. Такие мосты противоречат инкапсуляции и немного увеличивают размер программы, что может мешать пользователям и инструментам. Поэтому нам нужен более прямой, безопасный и прозрачный способ.

Больший косяк в том, что будут проблемы с отражением. IllegalAccessError сообщается при использовании java.lang.reflect.Method.invoke для вызова закрытого метода от одного соседа к другому. Это непонятно, потому что отражение должно иметь те же разрешения, что и доступ на уровне исходного кода.

Нечего сказать, посмотрите на код


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 файл класса использовал два атрибута InnerClasses и EnclosingMethod, чтобы помочь компилятору подтвердить отношение вложенности исходного кода.Каждый вложенный тип будет скомпилирован в свой собственный файл класса, а указанные выше атрибуты использовались для подключения других файлов классов. Этих свойств достаточно, чтобы JVM определяла отношения вложенности, но они не применимы напрямую к управлению доступом и слишком тесно связаны с языком Java.

Чтобы обеспечить более крупный и широкий вложенный тип, чем просто язык Java, и дополнить обнаружение управления доступом, вводятся два новых атрибута файла класса. Определены два типа элементов гнезда, один называется гнездовым хостом (также называемый классом верхнего уровня), который содержит атрибут NestMembers для определения других статических элементов гнезда, а другой — элемент гнезда, который содержит атрибут NestHost для определения его хозяин гнезда.

Вы можете взглянуть на детали файла класса приведенного выше кода.

Управление доступом JVM для вложенных членов

Скорректированы правила доступа к JVM и добавлены следующие термины:
Доступ к полю или методу R может быть получен классом или интерфейсом D тогда и только тогда, когда выполняется любое из следующих условий:

  • … (исходные условия остаются без изменений)
  • R является приватным и объявлен в другом классе или интерфейсе C, а C и D являются соседними.

C и D — имена таблиц соплеменников, и они должны иметь один и тот же хост.

Это правило свободного доступа будет действовать в следующих местах: (Я вставлю исходный текст в этот абзац, чувствую, что после перевода вкус изменится)

  • 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

Проверка вложенных классов

Вложенные классы должны быть проверены перед доступом. Проверка выполняется самое позднее перед доступом к членам, самое раннее при проверке файла класса или в промежутке между ними, например во время JIT. Чтобы проверить отношение вложенности, необходимо загрузить хост-класс гнезда.Чтобы предотвратить бессмысленную загрузку, этот шаг должен быть выполнен в конце, насколько это возможно.

В целях обеспечения целостности вложенности рекомендуется запретить модификацию атрибута файла класса вложенности.