Спецификация Java 11: 12.3. Связывание классов и интерфейсов

Связывание - это процесс принятия двоичной формы типа класса или интерфейса и объединения его в состояние выполнения виртуальной машины Java, чтобы его можно было выполнить. Класс или тип интерфейса всегда загружаются до связывания.

Связывание представлено тремя различными видами деятельности: проверка, подготовка и разрешение символических ссылок.

Точная семантика связывания дана в главе 5 спецификации виртуальной машины Java, Java SE 11 Edition. Здесь мы представляем обзор процесса с точки зрения языка программирования Java.

Эта спецификация обеспечивает гибкость реализации относительно того, когда происходит связывание действий (и, из-за рекурсии, загрузка), при условии, что соблюдается семантика языка программирования Java, что класс или интерфейс полностью проверены и подготовлены перед его инициализацией, и что ошибки, обнаруженные во время связывания, возникают в той точке программы, где программа выполняет какое-либо действие, которое может потребовать связывания с классом или интерфейсом, вовлеченным в ошибку.

Например, реализация может решить разрешать каждую символьную ссылку в классе или интерфейсе индивидуально, только когда она используется (ленивое или позднее разрешение), или разрешать их все сразу, пока класс проверяется (статическое разрешение). Это означает, что в некоторых реализациях процесс разрешения может продолжаться после инициализации класса или интерфейса.

Поскольку связывание включает выделение новых структур данных, оно может завершиться ошибкой OutOfMemoryError.

12.3.1. Проверка двоичного представления

Проверка гарантирует, что двоичное представление класса или интерфейса является структурно правильным. Например, она проверяет, что каждая инструкция имеет допустимый код операции; что каждая инструкция ветвления ведет к началу некоторой другой инструкции, а не к середине инструкции; что каждый метод имеет структурно правильную подпись; и что каждая инструкция подчиняется типовой дисциплине языка виртуальной машины Java.

Если во время проверки возникает ошибка, то экземпляр следующего подкласса класса LinkageError будет брошен в ту точку программы, которая вызвала проверку класса:

  • VerifyError: двоичному определению класса или интерфейса не удалось пройти набор необходимых проверок, чтобы убедиться, что он подчиняется семантике языка виртуальной машины Java и не может нарушить целостность виртуальной машины Java.

12.3.2. Подготовка класса или типа интерфейса

Подготовка включает создание статических полей (переменные и константы класса) для класса или интерфейса и инициализацию таких полей значениями по умолчанию (§4.12.5). Это не требует выполнения какого-либо исходного кода; явные инициализаторы для статических полей выполняются как часть инициализации (§12.4), а не подготовки.

Реализации виртуальной машины Java могут предварительно вычислить дополнительные структуры данных во время подготовки, чтобы сделать последующие операции над классом или интерфейсом более эффективными. Одна особенно полезная структура данных - это "таблица методов" или другая структура данных, которая позволяет вызывать любой метод для экземпляров класса без необходимости поиска суперклассов во время вызова.

12.3.3. Разрешение символических ссылок

Двоичное представление класса или интерфейса символически ссылается на другие классы и интерфейсы и их поля, методы и конструкторы, используя двоичные имена (§13.1) других классов и интерфейсов (§13.1). Для полей и методов эти символические ссылки включают имя класса или типа интерфейса, членом которого является поле или метод, а также имя самого поля или метода вместе с соответствующей информацией о типе.

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

Если во время разрешения возникнет ошибка, будет выдана ошибка. Чаще всего это будет экземпляр одного из следующих подклассов класса IncompatibleClassChangeError, но он также может быть экземпляром какого-либо другого подкласса IncompatibleClassChangeError или даже экземпляром самого класса IncompatibleClassChangeError. Эта ошибка может возникать в любой точке программы, которая прямо или косвенно использует символическую ссылку на тип:

  • IllegalAccessError: обнаружена символическая ссылка, которая указывает использование или назначение поля, или вызов метода, или создание экземпляра класса, к которому код, содержащий ссылку, не имеет доступа, потому что поле или метод были объявлены с private, protected или пакетным (package) доступом (не public) или потому, что класс не был объявлен public в пакете, который экспортируется или открывается в коде, содержащем ссылку.

    Это может произойти, например, если поле, которое изначально объявлено public, изменяется на private после того, как другой класс, который ссылается на это поле, был скомпилирован (§13.4.7); или если пакет, в котором объявлен public класс, перестает экспортироваться его модулем после того, как другой модуль, который ссылается на класс, был скомпилирован (§13.3).

  • InstantiationError: обнаружена символьная ссылка, которая используется в выражении создания экземпляра класса, но экземпляр не может быть создан, потому что ссылка оказывается ссылкой на интерфейс или абстрактный класс.

    Это может произойти, например, если класс, который изначально не был абстрактным, был изменен на абстрактный после того, как другой класс, который ссылается на рассматриваемый класс, был скомпилирован (§13.4.1).

  • NoSuchFieldError: Обнаружена символьная ссылка, которая относится к определенному полю определенного класса или интерфейса, но класс или интерфейс не содержат поля с таким именем.

    Это может произойти, например, если объявление поля было удалено из класса после того, как другой класс, который ссылается на это поле, был скомпилирован (§13.4.8).

  • NoSuchMethodError: Обнаружена символическая ссылка, которая относится к конкретному методу определенного класса или интерфейса, но класс или интерфейс не содержат метода этой подписи.

    Это может произойти, например, если объявление метода было удалено из класса после того, как другой класс, который ссылается на метод, был скомпилирован (§13.4.12).

Кроме того, UnsatisfiedLinkError, подкласс LinkageError, может быть брошен, если класс объявляет собственный метод, для которого не может быть найдена реализация. Ошибка возникнет, если метод используется, или раньше, в зависимости от того, какая стратегия разрешения используется реализацией виртуальной машины Java (§12.3).


Читайте также:


Комментарии

Популярные сообщения из этого блога

Методы класса Object в Java

Как получить текущий timestamp в Java

Основные опции JVM для повышения производительности и отладки