Как "instanceof" реализован в JVM?
Использует ли он рефлексию, и если да, что происходит за кулисами?
2 ответа
Джон прав насчет того, как оператор отображает байт-код. Что касается реализаций, большинство JVM представляют объекты в памяти как помеченные объединения загруженных конкретных классов:
теговое объединение, также называемое вариантом, записью варианта, дискриминационным объединением, непересекающимся объединением или типом суммы, представляет собой структуру данных, используемую для хранения значения, которое может принимать несколько различных, но фиксированных типов.
Так x instanceof MyClassType
можно ответить, посмотрев на разреженную логическую матрицу, бит которой установлен, когда конкретный тип является экземпляром типа класса.
x instanceof InterfaceType
это немного сложнее, но аналогичные методы могут помочь с этим тоже.
JVM может хранить в памяти большую разреженную матрицу со строкой по номинальным типам (типам классов или интерфейсов) и столбцам по типам классов.
Например:
[all nominal types]
Object String Integer Number Comparable Iterable ...
[only String ✓ ✓ ✓
concrete Integer ✓ ✓ ✓ ✓
types] ...
Когда JVM должна собирать классы, поддерживать эту матрицу становится сложнее, поэтому обычно вы сохраняете строку с объектом класса.
Прокси-классы - это интересный случай, но я думаю, что определение прокси-класса предполагает генерацию некоторого байтового кода во время выполнения, который затем проходит через обычную систему загрузки классов в большинстве JVM.
В основном это часть набора инструкций JVM - есть instanceof
инструкция. Так, например, такой метод:
public static void checkString(Object x) {
if (x instanceof String) {
System.out.println("Foo");
}
}
составлен в:
public static void checkString(java.lang.Object);
Code:
0: aload_0
1: instanceof #2 // class java/lang/String
4: ifeq 15
7: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
10: ldc #4 // String Foo
12: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
15: return
}
(Это просто вывод javap
.)
В спецификации JVM есть детали того, что должна делать инструкция. См. Раздел 6.5 для точных деталей инструкции. Как это реализовано, зависит от реализации виртуальной машины, но одним примером реализации может быть:
- Проверьте, является ли первый операнд
null
(и вернутьсяfalse
если так) - Найдите тип времени выполнения объекта, на который ссылается первый операнд.
- Перемещайтесь вверх по иерархии типов (включая реализованные интерфейсы), пока не сможете доказать, что фактический тип либо совместим, либо несовместим со вторым операндом.