Отражение массива Java: isArray против instanceof

177

Есть ли предпочтения или различия в поведении между использованием:

if(obj.getClass().isArray()) {}

и

if(obj instanceof Object[]) {}

?

Дэвид Цитрон
источник

Ответы:

203

В большинстве случаев вы должны использовать instanceofоператор, чтобы проверить, является ли объект массивом.

Как правило, вы проверяете тип объекта, прежде чем переходить к определенному типу, который известен во время компиляции. Например, возможно, вы написали некоторый код, который может работать с Integer[]или int[]. Вы бы хотели охранять свои заклинания с помощью instanceof:

if (obj instanceof Integer[]) {
    Integer[] array = (Integer[]) obj;
    /* Use the boxed array */
} else if (obj instanceof int[]) {
    int[] array = (int[]) obj;
    /* Use the primitive array */
} else ...

На уровне JVM instanceofоператор выполняет преобразование в определенный байт-код instanceof , который оптимизирован в большинстве реализаций JVM.

В более редких случаях вы можете использовать отражение для обхода графа объектов неизвестных типов. В подобных случаях isArray()метод может быть полезен, потому что вы не знаете тип компонента во время компиляции; вы можете, например, реализовать какой-то механизм сериализации и иметь возможность передавать каждый компонент массива к одному и тому же методу сериализации, независимо от типа.

Есть два особых случая: нулевые ссылки и ссылки на примитивные массивы.

Нулевая ссылка приведет instanceofк результату false, пока isArrayвыбрасывает a NullPointerException.

Применительно к примитивному массиву instanceofвыдает результат, falseесли только тип компонента в правом операнде точно не соответствует типу компонента. Напротив, isArray()вернется trueдля любого типа компонента.

Эриксон
источник
7
Да, но сколько это изменит? Это звучит как микрооптимизация для меня.
Майкл Майерс
2
@Dims Если вы утверждаете , что obj instanceof int[]урожаи , falseкогда вы назначаете int[]к obj, вы ошибаетесь.
erickson
4
Извините, я имел в виду, что obj instanceof Object[]дает, falseесли Object obj = new int[7].
Димс
3
Да, в Java примитивные типы данных не являются объектами и не расширяются java.lang.Object, так что это имеет смысл. Но instanceofвсе еще может использоваться для проверки примитивных массивов.
erickson
4
-1: В общем, поскольку примитивные массивы являются массивами, isArray()следует использовать вызовы . В очень не общем частном случае наличия только массивов объектов instanceofобеспечивает высокую производительность альтернативы.
Сэм Харвелл,
33

В последнем случае, если obj равен null, вы не получите NullPointerException, а false.

Буркхард
источник
8

Если objимеет тип int[]сказать, то это будет иметь массив, Classно не будет экземпляром Object[]. Итак, что вы хотите сделать с obj. Если вы собираетесь разыграть его, продолжайте instanceof. Если вы собираетесь использовать отражение, тогда используйте .getClass().isArray().

Том Хотин - Tackline
источник
4

getClass().isArray() значительно медленнее в Sun Java 5 или 6 JRE, чем в IBM.

Настолько, что использование clazz.getName().charAt(0) == '['быстрее на Sun JVM.

Себастьян Тардиф
источник
10
Есть ли у вас какая-либо статистика, тематическое исследование или другие доказательства, на которые вы можете ссылаться?
Дэвид Цитрон
4

Недавно я столкнулся с проблемой при обновлении приложения Groovy с JDK 5 до JDK 6. Не isArray()удалось использовать в JDK6:

MissingMethodException:
No signature of sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl.isArray() ...

Меняется, чтобы instanceof Object[]исправить это.

dturanski
источник
Это не имеет никакого смысла. isArrayэто метод Class, нет Type, поэтому, конечно GenericArrayTypeImpl, не имеет этот метод. И getClassникогда не сможет вернуть не- Class Type, так что вы (или Groovy ??), должно быть, сделали что-то не так, чтобы получить это, например, предположив, что каждый Type- это Class.
kaqqao
3

Отражение массива Java предназначено для случаев, когда у вас нет экземпляра Class, доступного для выполнения instanceof. Например, если вы пишете какую-то инфраструктуру внедрения, которая внедряет значения в новый экземпляр класса, такой как JPA, то вам нужно использовать функциональность isArray ().

Я писал об этом в начале декабря. http://blog.adamsbros.org/2010/12/08/java-array-reflection/

Трентон Д. Адамс
источник
2

Если у вас когда-либо есть выбор между отражающим решением и неотражающим решением, никогда не выбирайте отражающее решение (включая объекты класса). Дело не в том, что это «неправильно» или что-то в этом роде, но все, что связано с отражением, обычно менее очевидно и менее ясно.

Билл К
источник
Ну, "instanceof" также является своего рода отражением (или, по крайней мере, самоанализом), но я понимаю вашу точку зрения.
Дэвид Цитрон
Кроме того, как правило, медленнее.
Безумный физик
0

Нет никакой разницы в поведении, которое я могу найти между этими двумя (кроме очевидного нулевого случая). Что касается какой версии отдать предпочтение, я бы пошел со второй. Это стандартный способ сделать это в Java.

Если это смущает читателей вашего кода (потому что String[] instanceof Object[]это правда), вы можете использовать первое, чтобы быть более явным, если рецензенты кода продолжают спрашивать об этом.

hazzen
источник