Влияние производительности использования instanceof в Java

В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.

При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.

Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».

Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this. Возьмем этот пример:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

И в другом месте вашего кода:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference и otherReference оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.

299
задан JSK NS 28 December 2014 в 23:27
поделиться

16 ответов

Современные компиляторы JVM/JIC удалили хит производительности большинства традиционно "медленных" операций, включая instanceof, обработку исключений, отражение, и т.д.

, Как Donald Knuth записал, "Мы должны забыть о маленькой эффективности, сказать приблизительно 97% времени: преждевременная оптимизация является корнем всего зла". Производительность instanceof, вероятно, не будет проблемой, не тратьте впустую свое время, придумывающее экзотические обходные решения, пока Вы не уверены, что это - проблема.

260
ответ дан Steve 23 November 2019 в 01:29
поделиться

Вы фокусируетесь на неправильной вещи. Различие между instanceof и любым другим методом для проверки того же самого, вероятно, даже не было бы измеримо. Если производительность очень важна тогда, Java является, вероятно, неправильным языком. Основная причина, являющаяся этим, которым Вы не можете управлять, когда VM решает его, хочет пойти, собирают мусор, который может взять ЦП к 100% в течение нескольких секунд в большой программе (MagicDraw 10 был большим для этого). Если Вы не будете управлять каждым компьютером, эта программа будет работать, Вы не можете гарантировать, какая версия JVM это будет идти, и многие более старые имели главные проблемы скорости. Если это - небольшое приложение, можно согласиться с Java, но если Вы постоянно считаете и отбросите данные тогда, то Вы будете уведомление, когда GC умрет.

-3
ответ дан tloach 23 November 2019 в 01:29
поделиться

Относительно примечания Peter Lawrey, что Вы не нуждаетесь в instanceof для заключительных классов и можете просто использовать ссылочное равенство, быть осторожными! Даже при том, что заключительные классы не могут быть расширены, они, как гарантируют, не будут загружены тем же classloader. Только используйте x.getClass () == SomeFinal.class или его род, если Вы абсолютно положительны, что существует только один classloader в игре для того раздела кода.

0
ответ дан 23 November 2019 в 01:29
поделиться

Необходимо иметь размеры/представлять, если это - действительно проблема производительности в проекте. Если это, я рекомендовал бы модернизация - если это возможно. Я вполне уверен, Вы не можете победить собственную реализацию платформы (записанный в C). Необходимо также рассмотреть множественное наследование в этом случае.

необходимо сказать больше о проблеме, возможно, Вы могли использовать ассоциативное хранилище, например, Map< Класс, Объект>, если Вы только интересуетесь конкретными типами.

0
ответ дан Karl 23 November 2019 в 01:29
поделиться

В современной версии Java оператор instanceof быстрее как вызов простого метода. Это означает:

if(a instanceof AnyObject){
}

быстрее как:

if(a.getType() == XYZ){
}

Другая вещь состоит в том, если необходимо расположить каскадом много instanceof. Тогда переключатель, которые только звонят однажды getType () быстрее.

2
ответ дан Horcrux7 23 November 2019 в 01:29
поделиться

Обычно причина, почему "instanceof" оператор осужден в случае как этот (где instanceof проверяет на подклассы этого базового класса) состоит в том, потому что то, что необходимо делать, перемещает операции в метод и сверхизбавляет его для соответствующих подклассов. Например, если Вы имеете:

if (o instanceof Class1)
   doThis();
else if (o instanceof Class2)
   doThat();
//...

можно заменить это

o.doEverything();

и затем иметь реализацию "doEverything ()" в вызове Class1 "doThis ()", и в вызове Class2 "doThat ()", и так далее.

2
ответ дан Paul Tomblin 23 November 2019 в 01:29
поделиться

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

if (o instanceof java.lang.String)

мог бы быть с такой скоростью, как следующий код C

if (objectStruct->iAmInstanceOf == &java_lang_String_class)

предположение, что JIT-компилятор существует и делает достойное задание.

Рассмотрение, что это только получает доступ к указателю, получая указатель при определенном смещении указатель, указывает на и сравнивая это с другим указателем (который является в основном тем же как тестирующий к числам на 32 бита, являющимся равным), я сказал бы, что операция может на самом деле быть очень быстрой.

Это не имеет к, тем не менее, это во многом зависит от JVM. Однако, если бы это оказалось бы операцией узкого места в Вашем коде, я считал бы реализацию JVM довольно плохой. Даже тот, который не имеет никакого JIT-компилятора и только интерпретирует код, должен быть в состоянии сделать тест instanceof в фактически никакое время.

3
ответ дан Mecki 23 November 2019 в 01:29
поделиться

InstanceOf является предупреждением плохого Объектно-ориентированного проектирования.

Текущие JVMs означают , instanceOf не является большой частью беспокойства производительности сам по себе. Если Вы используете его много, специально для базовой функциональности, пора, вероятно, посмотреть на дизайн. Производительность (и простота/пригодность для обслуживания) усиления рефакторинга к лучшему дизайну значительно перевесит любые фактические циклы процессора, потраченные на фактическое вызов instanceOf.

Для предоставления очень небольшого упрощенного примера программирования.

if (SomeObject instanceOf Integer) {
  [do something]
}
if (SomeObject instanceOf Double) {
  [do something different]
}

плохая архитектура, лучший выбор состоял бы в том, чтобы сделать, чтобы SomeObject был родительским классом двух дочерних классов, где каждый дочерний класс переопределяет метод (doSomething), таким образом, код выглядел бы как таковым:

Someobject.doSomething();
2
ответ дан Demian Krige 23 November 2019 в 01:29
поделиться

Demian и Paul упоминают положительный момент; однако , размещение кода для выполнения действительно зависит от того, как Вы хотите использовать данные...

я - большой поклонник маленьких объектов данных, которые могут использоваться во многих отношениях. Если Вы следуете за переопределением (полиморфный) подход, Ваши объекты могут только использоваться "один путь".

Это - то, где шаблоны входят...

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

я предпочитаю использовать стратегическую модель, где можно зарегистрировать стратегии каждого подтипа, Вы хотите обработать. Что-то как следующее. Обратите внимание, что это только помогает для точных соответствий типа, но имеет преимущество, что это расширяемо - сторонние участники могут добавить свои собственные типы и обработчики. (Это хорошо для динамических платформ как OSGi, где новые пакеты могут быть добавлены)

, Надо надеяться, это вдохновит некоторые другие идеи...

package com.javadude.sample;

import java.util.HashMap;
import java.util.Map;

public class StrategyExample {
    static class SomeCommonSuperType {}
    static class SubType1 extends SomeCommonSuperType {}
    static class SubType2 extends SomeCommonSuperType {}
    static class SubType3 extends SomeCommonSuperType {}

    static interface Handler<T extends SomeCommonSuperType> {
        Object handle(T object);
    }

    static class HandlerMap {
        private Map<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>> handlers_ =
            new HashMap<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>>();
        public <T extends SomeCommonSuperType> void add(Class<T> c, Handler<T> handler) {
            handlers_.put(c, handler);
        }
        @SuppressWarnings("unchecked")
        public <T extends SomeCommonSuperType> Object handle(T o) {
            return ((Handler<T>) handlers_.get(o.getClass())).handle(o);
        }
    }

    public static void main(String[] args) {
        HandlerMap handlerMap = new HandlerMap();

        handlerMap.add(SubType1.class, new Handler<SubType1>() {
            @Override public Object handle(SubType1 object) {
                System.out.println("Handling SubType1");
                return null;
            } });
        handlerMap.add(SubType2.class, new Handler<SubType2>() {
            @Override public Object handle(SubType2 object) {
                System.out.println("Handling SubType2");
                return null;
            } });
        handlerMap.add(SubType3.class, new Handler<SubType3>() {
            @Override public Object handle(SubType3 object) {
                System.out.println("Handling SubType3");
                return null;
            } });

        SubType1 subType1 = new SubType1();
        handlerMap.handle(subType1);
        SubType2 subType2 = new SubType2();
        handlerMap.handle(subType2);
        SubType3 subType3 = new SubType3();
        handlerMap.handle(subType3);
    }
}
4
ответ дан Scott Stanchfield 23 November 2019 в 01:29
поделиться

Instanceof очень быстр. Это сводится к байт-коду, который используется для сравнения ссылки класса. Попробуйте несколько миллионов instanceofs в цикле и лично убедитесь.

4
ответ дан Apocalisp 23 November 2019 в 01:29
поделиться

'instanceof' является на самом деле оператором, как + или - и я полагаю, что он имеет свою собственную инструкцию по байт-коду JVM. Это должно быть много быстро.

я не должен что, если у Вас есть переключатель, где Вы тестируете, если объект является экземпляром некоторого subsclass, то Ваш дизайн, возможно, должен был бы быть переделан. Рассмотрите снижение определенного для подкласса поведения в сами подклассы.

4
ответ дан Outlaw Programmer 23 November 2019 в 01:29
поделиться

instanceof, вероятно, будет более дорогостоящим, чем простое равняется в наиболее реальных внедрениях (то есть, те, где instanceof действительно необходим, и Вы не можете только решить его путем переопределения общепринятой методики, как каждый учебник новичка, а также Demian выше предлагают).

, Почему это? Поскольку, что, вероятно, собирается произойти, то, что у Вас есть несколько интерфейсов, которые обеспечивают некоторую функциональность (скажем, x интерфейсов, y и z), и некоторые объекты управлять, который может (или не) реализуют один из тех интерфейсов..., но не непосредственно. Скажите, например, я имею:

w расширяет x

, w

B реализаций А расширяется

, C расширяет B, y

D реализаций расширяет C, z

реализаций предположим, что я обрабатываю экземпляр D, объект d. Вычисления (d instanceof x) требуют для взятия d.getClass (), циклично выполняют через интерфейсы, которые это реализует, чтобы знать, является ли каждый == к x, и если не делают так снова рекурсивно для всех их предков... В нашем случае, если Вы делаете исследование в ширину того дерева, приводит по крайней мере к 8 сравнениям, предполагая y, и z ничего не расширяют...

сложность реального дерева вывода, вероятно, будет выше. В некоторых случаях JIT может оптимизировать большую часть из него далеко, если это может решить заранее d как являющийся, во всех возможных случаях, экземпляре чего-то, что расширяет x. Реалистично, однако, Вы собираетесь пройти тот обход дерева большую часть времени.

, Если бы это становится проблемой, я предложил бы использовать карту обработчика вместо этого, связав реальный класс объекта к закрытию, которое делает обработку. Это удаляет фазу обхода дерева в пользу прямого отображения. Однако остерегайтесь этого при установке обработчика для C.class мой объект d выше не будет распознан.

вот мои 2 цента, я надеюсь, что они помогают...

5
ответ дан 23 November 2019 в 01:29
поделиться

Я просто сделал простой тест, чтобы видеть, как instanceOf производительность по сравнению с простым s.equals (), звонят в строковый объект только с одной буквой.

в 10.000.000 циклично выполняются, instanceOf дал мне 63-96ms, и строка равняется, дал мне 106-230ms

, я использовал java jvm 6.

Так в моем простом тесте быстрее, чтобы сделать instanceOf вместо одного сравнения символьной строки.

.equals Целого числа использования () вместо строки дал мне тот же результат, только когда я использовал ==, я был быстрее, чем instanceOf на 20 мс (в 10 000 000 циклов)

73
ответ дан 23 November 2019 в 01:29
поделиться

Ответ на Ваш самый последний вопрос: Если профилировщик не говорит Вам, что Вы проводите смешное количество времени в instanceof: Да, Вы придираетесь к мелочам.

Прежде, чем задаться вопросом об оптимизации чего-то, что никогда не должно было оптимизироваться: Запишите свой алгоритм самым читаемым способом и выполните его. Выполните его, пока компилятор монеты в пять центов не получит шанс оптимизировать его сам. Если у Вас тогда есть проблемы с этой частью кода, используйте профилировщика, чтобы сказать Вам, где получить большинство и оптимизировать это.

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

И в истинном духе этого ответа (которому я от чистого сердца верю): Я абсолютно не знаю, как instanceof и == имеют отношение, как только компилятор монеты в пять центов получил шанс оптимизировать его.

я забыл: Никогда не измеряйте первый показ.

18
ответ дан Olaf Kock 23 November 2019 в 01:29
поделиться

instanceof очень эффективен, таким образом, Ваша производительность вряд ли пострадает. Однако использование большого количества instanceof предлагает вопросы проектирования.

, Если можно использовать xClass == String.class, это быстрее.Примечание: Вам не нужен instanceof для заключительных классов.

4
ответ дан Peter Lawrey 23 November 2019 в 01:29
поделиться

Элементы, которые будут определять влияние на производительность:

  1. Количество возможных классов, для которых оператор instanceof может вернуть истину
  2. Распределение ваших данных - это большая часть instanceof операции разрешились с первой или второй попытки? Вы захотите поставить на первое место ваши наиболее вероятные верные операции.
  3. Среда развертывания. Работа на виртуальной машине Sun Solaris значительно отличается от JVM Sun Windows. По умолчанию Solaris будет работать в «серверном» режиме, а Windows - в клиентском. Оптимизация JIT в Solaris сделает доступ ко всем методам одинаковым.

Я создал микробенчмарк для четырех различных методов отправки . Результаты Solaris следующие, меньшее число быстрее:

InstanceOf 3156
class== 2925 
OO 3083 
Id 3067 
19
ответ дан 23 November 2019 в 01:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: