Класс Sub
является подклассом класса Sup
. Что это значит практически? Или, другими словами, каково практическое значение слова «наследование»?
Вариант 1: Код из Sup фактически скопирован в Sub. (как в 'copy-paste', но без скопированного кода, визуально видимого в подклассе).
Пример: methodA()
метод изначально в Sup. Sub расширяет Sup, поэтому methodA()
(виртуально) копируется в Sub. Теперь у Sub есть метод с именем methodA()
. Он идентичен Sup methodA()
в каждой строке кода, но полностью принадлежит Sub - и не зависит от Sup или связан с Sup каким-либо образом.
Вариант 2: Код из Sup на самом деле не копируется в Sub. Это все еще только в суперклассе. Но этот код может быть доступен через подкласс и может использоваться подклассом.
Пример: methodA()
это метод в Sup. Sub расширяет Sup, так что теперь methodA()
можно получить через Sub следующим образом: subInstance.methodA()
. Но это на самом деле вызовет methodA()
в суперклассе. Это означает, что methodA () будет работать в контексте суперкласса, даже если он был вызван подклассом.
Вопрос: Какой из двух вариантов действительно работает? Если ни один из них не подходит, то, пожалуйста, опишите, как эти вещи на самом деле работают.
источник
Ответы:
Вариант 2
На байт-код ссылаются динамически во время выполнения: именно поэтому, например, происходят ошибки LinkageErrors .
Например, предположим, что вы скомпилировали два класса:
Теперь измените и перекомпилируйте родительский класс без изменения или перекомпиляции дочернего класса :
Наконец, запустите программу, которая использует дочерний класс. Вы получите NoSuchMethodError :
источник
Давайте начнем с двух простых классов:
а потом
Компилируя methodA и глядя на байт-код, мы получаем:
И вы можете сразу увидеть с помощью метода invokespecial, который выполняет поиск в методе класса SupA ().
Код операции invokespecial имеет следующую логику:
В этом случае не существует метода экземпляра с тем же именем и дескриптором в его классе, поэтому первая пуля не сработает. Вторая пуля, однако, будет - есть суперкласс, и он вызывает метод суперА.
Компилятор этого не делает, и в классе нет копии источника Sup.
Однако история еще не закончена. Это просто скомпилированный код. Как только код попадет в JVM, HotSpot может подключиться.
К сожалению, я не очень много знаю об этом, поэтому я обращусь к авторитету по этому вопросу и перейду к Inlining in Java, где говорится, что HotSpot может использовать встроенные методы (даже не финальные).
Переходя к документам, отмечается, что если конкретный вызов метода становится горячей точкой вместо того, чтобы выполнять этот поиск каждый раз, эта информация может быть встроена - эффективно копируя код из Sup methodA () в Sub methodA ().
Это делается во время выполнения, в памяти, в зависимости от поведения приложения и оптимизации, необходимой для повышения производительности.
Как указано в HotSpot Internals for OpenJDK, «методы часто являются встроенными. Статические, частные, окончательные и / или« специальные »вызовы легко встроить».
Если вы покопаетесь в опциях для JVM, вы найдете опцию
-XX:MaxInlineSize=35
(35 по умолчанию), которая является максимальным числом байтов, которое может быть встроено. Я укажу, что именно поэтому Java любит иметь много маленьких методов - потому что они могут быть легко встроены. Эти маленькие методы становятся быстрее, когда их вызывают больше, потому что они могут быть встроены. И хотя с этим числом можно играть и увеличивать его, другие оптимизации могут быть менее эффективными. (связанный вопрос SO: стратегия встраивания HotSpot JIT, которая указывает на ряд других вариантов, чтобы взглянуть на внутреннюю часть встраивания, которую делает HotSpot).Итак, нет - код не встроен во время компиляции. И да - код вполне может быть встроен во время выполнения, если этого требует оптимизация производительности.
И все, что я пишу о встраивании HotSpot, относится только к HotSpot JVM, распространяемой Oracle. Если вы посмотрите на список виртуальных машин Java в Википедии, существует гораздо больше, чем просто HotSpot, и способ, которым эти JVM обрабатывают встраивание, может полностью отличаться от того, что я описал выше. Apache Harmony, Dalvik, ART - там все может работать по-другому.
источник
код не копируется, доступ к нему осуществляется по ссылке:
компиляторы могут оптимизировать то, как это представляется / выполняется в памяти, но это в основном структура
источник