В моем приложении obj.getClass().isArray()
вызывается очень часто и становится узким местом приложения.
Я хочу эффективно проверить во время выполнения, если объект является массивом.
Примитивный массив и массив объектов должны возвращать true.
То, как я могу себе представить, - это instanceof
все примитивные массивы, но не может обрабатывать такие типы, как int [] []. И приложение используется как lib, поэтому я не могу перечислить все типы.
Есть ли ключ к этому?
Object.isArray() медленный, есть ли быстрый способ сделать это?
Ответ 1
Тест, который я только что сделал, дал следующие результаты:
{s instanceof Object[]} spends 44ms
{s.getClass().getName().charAt(0) == '['} spends 58ms
{s.getClass().isArray()} spends 303ms
Бенчмарк был выполнен с использованием Benchmark.java, который называется Main. Java.
После обсуждения использования переменной final
в приведенном выше тесте см. новые результаты с использованием локального:
{s instanceof Object[]} spends 83ms
{s.getClass().getName().charAt(0) == '['} spends 93ms
{s.getClass().isArray()} spends 354ms
Даже если длительность еще немного (интересная кстати), их порядок сохранен.
Затем Benchmark.java вызывается с помощью этого нового Main.java.
И используя примитивный массив, вызываемый с помощью этого другого Main.java:
{a instanceof int[]} spends 71ms
{a.getClass().getName().charAt(0) == '['} spends 82ms
{a.getClass().isArray()} spends 340ms
Все тот же порядок результатов.
Ответ 2
isArray()
- наиболее эффективный способ проверить, является ли объект экземпляром массива во время выполнения. Если производительность является проблемой, вы можете использовать один из следующих способов для ее устранения:
- Восстановите свой код, поэтому объекты массива и объекты без массива обрабатываются отдельно, поэтому результаты
isArray()
известны во время компиляции. - Используйте локальные переменные и/или аргументы для кэширования значения
isArray()
во время операции, поэтому его нужно только вызывать один раз.
Ответ 3
Из ваших комментариев, я заключаю, что вы можете страдать от интерпретирующей ошибки при исследовании результатов профилирования. Инструментальное устройство уровня профилировщика может сильно искажать вызовы getClass()
и isArray()
, а не выражаться выражениями instanceof
. Другими словами, вы, вероятно, измеряете накладные расходы вашего профилировщика здесь.
Кроме того, в быстрых тестах я не могу поддержать ваше требование. Я выполнил следующий, очень глупый тест:
public class Test {
public static void main(String[] args) {
final int rep = 10000000;
Object[] o = {
null,
1,
"x",
new Object[0],
new Object[0][],
new int[0],
new int[0][]
};
// "Warmup" to avoid potential JVM startup overhead
long x = 0;
for (int i = 0; i < rep; i++) {
x+=checkInstanceOf(o);
}
for (int i = 0; i < rep; i++) {
x+=checkIsArray(o);
}
for (int i = 0; i < rep; i++) {
x+=checkClassName(o);
}
// Actual test
long t1 = System.nanoTime();
for (int i = 0; i < rep; i++) {
x+=checkInstanceOf(o);
}
long t2 = System.nanoTime();
for (int i = 0; i < rep; i++) {
x+=checkIsArray(o);
}
long t3 = System.nanoTime();
for (int i = 0; i < rep; i++) {
x+=checkClassName(o);
}
long t4 = System.nanoTime();
System.out.println(t2 - t1);
System.out.println(t3 - t2);
System.out.println(t4 - t3);
}
private static int checkInstanceOf(Object[] o) {
int i = 0;
for (Object x : o) {
if (x instanceof Object[]) i++; // Perform some logic
else if (x instanceof boolean[]) i++; // to keep the compiler or
else if (x instanceof byte[]) i++; // the JVM from optimising
else if (x instanceof short[]) i++; // this code away
else if (x instanceof int[]) i++;
else if (x instanceof long[]) i++;
else if (x instanceof float[]) i++;
else if (x instanceof double[]) i++;
else if (x instanceof char[]) i++;
}
return i;
}
private static int checkIsArray(Object[] o) {
int i = 0;
for (Object x : o) {
if (x != null && x.getClass().isArray()) i++;
}
return i;
}
private static int checkClassName(Object[] o) {
int i = 0;
for (Object x : o) {
if (x != null && x.getClass().getName().charAt(0) == '[') i++;
}
return i;
}
}
Я получаю:
394433000 // instanceof
110655000 // getClass().isArray()
396039000 // getClass().getName().charAt(0) == '['
Таким образом, вы обычно не можете требовать getClass().isArray()
быть медленнее, чем тщательный набор проверок instanceof
. Конечно, есть много разных способов переписать мой тест, но вы получите эту идею.