Путаница в инструкции по проверке байт-кода? - PullRequest
12 голосов
/ 11 февраля 2011

Я работаю над собственной реализацией JVM и пришел к инструкции checkcast.Полная документация на этой странице .Мне любопытно, потому что при перечислении правил о том, как работает приведение, одно условие проверяется, если проверяемая ссылка на объект имеет тип интерфейса.Насколько я понимаю, это не должно быть возможно;интерфейсы не могут быть созданы напрямую, и любой объект, который реализует интерфейс, имеет какой-то другой конкретный тип класса.Я что-то упустил?

Ответы [ 2 ]

22 голосов
/ 11 февраля 2011

Похоже, вы были не единственными, кто запутался в этом определении, у этого поста есть объяснение: http://mbravenboer.blogspot.com/2008/12/why-jvm-spec-defines-checkcast-for.html

Оказывается, это действительно "невозможный" случай.Причина, по которой этот элемент содержится в спецификации, заключается в том, что checkcast рекурсивно определяется для массивов:

  • Если S - это класс, представляющий тип массива SC [], то есть массив компонентов типаSC, тогда:
  • ...
  • Если T является массивом типа TC [], то есть массивом компонентов типа TC, то должно выполняться одно из следующих условий:
    • ...
    • TC и SC являются ссылочными типами, а тип SC может быть приведен к TC путем рекурсивного применения этих правил.

Итак, если у вас есть объект типа List [], приведенный к Collection [], то правила для checkcast рекурсивно вызываются для типов S = List и T = Collection.Обратите внимание, что List является интерфейсом, но объект может иметь тип List [] во время выполнения.Если вы не проверили это с сопровождающими JVM Spec, но, насколько я вижу, это единственная причина, по которой существует правило для типов интерфейсов.

0 голосов
/ 11 февраля 2011

Если S является типом интерфейса, то:

Если T является типом класса, то T должен быть Object (§2.4.7).
Если T является типом интерфейса, то T должен быть тем же интерфейсом, что и S, или суперинтерфейсом S (§2.13.2).

Мне кажется, это понятно: интерфейс может быть преобразован в расширенный интерфейс. Этот случай используется, например, когда вы вызываете сериализацию для DataInputStream: интерфейс DataInputStream реализует Serializable, поэтому мы приводим объект к Serializable, даже не зная, что является реализованным классом объекта.

...