Как работает `isInstanceOf`?
Предположим, что:
class B
class A extends B
trait T
Тогда оно выполняется:
val a: A with T = new A with T
a.isInstanceOf[B] // result is true !
Можно ли сказать, что метод isInstanceOf
проверяет, существует ли хотя бы один тип (не все типы), который соответствует правой стороне в отношении подтипа?
Сначала я думал, что значение с типом A with T
не может быть подтипом B
, потому что A
и T
не оба подтипа B
. Но это A
или T
является подтипом B
- это правильно?
Ответы
Ответ 1
isInstanceOf
выглядит, если в цепочке наследования есть соответствующая запись. Цепочка A with T
включает A
, B
и T
, поэтому a.isInstanceOf[B]
должно быть истинным.
изменить:
На самом деле сгенерированный байт-код вызывает javas instanceof
, поэтому в java он будет a instanceof B
. Более сложным вызовом типа a.isInstanceOf[A with T]
будет (a instanceof A) && (a instanceof T)
.
Ответ 2
Сначала я подумал, что значение с типом A с T не может быть подтип B
Здесь есть два неправильных представления. Во-первых, что статический тип экземпляра имеет какое-либо отношение к результату isInstanceOf
: его нет. Чтобы быть ясным, при выполнении a.isInstanceOf[B]
факт, что a
имеет тип A with T
, не имеет значения.
Метод isInstanceOf
реализуется на уровне байт-кода JVM. Он рассматривает информацию о классе, которую несет каждый экземпляр, и проверяет, является ли B
одним из классов (класс самого экземпляра и его предков) или одним из реализованных интерфейсов. Что отношение "есть-a": "a есть B".
Технически, isInstanceOf
является частью отражения Java, где он известен как instanceof
.
Второе заблуждение - наследование может каким-то образом удалить родительский тип. Этого никогда не бывает: наследование только добавляет типы, никогда не удаляет их. Тип A with T
- это a
, a B
, a T
, a AnyVal
и a Any
. Поэтому даже если isInstanceOf
посмотрел тип A with T
, он все равно вернет true.