Я работаю над собственной реализацией 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, даже не зная, что является объектом, реализованным классом.