Путаница в инструкции по байтовому чеку?

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

Ответ 1

Кажется, вы не единственное, кто смутил это определение, в этом сообщении в блоге есть объяснение: 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, но, насколько я вижу, это единственная причина, по которой существует правило для типов интерфейсов.

Ответ 2

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

Если T - тип класса, то T должен быть Объектом (п. 2.4.7).
Если T - тип интерфейса, то T должен быть тем же интерфейсом, что и S, или суперинтерфейсом S (§ 2.2.13).

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