instanceof против getClass ()

114

Я вижу прирост производительности при использовании оператора getClass()и оператора.==instanceOf

Object  str = new Integer("2000");

long starttime = System.nanoTime();

if(str instanceof String) {
    System.out.println("its string");
} else {
    if (str instanceof Integer) {
        System.out.println("its integer");

    }
}

System.out.println((System.nanoTime()-starttime));

starttime = System.nanoTime();

if(str.getClass() == String.class) {
    System.out.println("its string in equals");
} else {
    if(str.getClass() == Integer.class) {
        System.out.println("its integer");
    }
}

System.out.println((System.nanoTime()-starttime));

Есть ли какие-то рекомендации, какие использовать getClass()или instanceOf?

Учитывая сценарий: Я знаю точно классы должны быть совпавшие, то есть String, Integer(это конечные классы) и т.д.

Использование instanceOfоператора - плохая практика?

капля
источник
3
Это объясняется в: stackoverflow.com/questions/596462/… .
Clement P
2
Ваш метод отсчета времени вызывает искусственные задержки и дает неверные результаты отсчета времени. Поменяйте местами порядок выполнения проверок, и вы увидите, что первая выполняемая вами проверка (== или instanceof) всегда будет длиннее. Я предполагаю, что это println () s. Вы никогда не должны включать это в свой временной блок.
kurtzmarc
Всего лишь один комментарий, чтобы сравнить производительность, используйте несколько итераций цикла (например, 10000), чтобы повысить точность. Один единственный вызов - не лучшая мера.
martins.tuga

Ответы:

139

Причина, по которой производительность instanceofи getClass() == ...отличается, в том, что они делают разные вещи.

  • instanceofпроверяет, является ли ссылка на объект в левой части (LHS) экземпляром типа в правой части (RHS) или каким-либо подтипом .

  • getClass() == ... проверяет идентичность типов.

Поэтому рекомендуется игнорировать проблему производительности и использовать альтернативу, которая дает вам нужный ответ.

Использование instanceOfоператора - плохая практика?

Не обязательно. Чрезмерное использование любого из них instanceOfили getClass() может быть «дизайнерским запахом». Если вы не будете осторожны, вы получите проект, в котором добавление новых подклассов приведет к значительному изменению кода. В большинстве случаев предпочтительным подходом является использование полиморфизма.

Однако бывают случаи, когда это НЕ «дизайнерский запах». Например, equals(Object)вам нужно проверить фактический тип аргумента и вернуть falseего, если он не совпадает. Лучше всего это делать с помощью getClass().


Такие термины, как «передовой опыт», «плохая практика», «запах дизайна», «антипаттерн» и т. Д. Следует использовать осторожно и относиться к ним с подозрением. Они поощряют черно-белое мышление. Лучше делать свои суждения в контексте, а не основываться исключительно на догмах; например, то, что кто-то сказал, является «лучшей практикой».

Стивен С
источник
@StephenC Как вы сказали, он code smellдолжен использовать то же самое. Это означает, что это следствие плохого дизайна (неполиморфного) кода, который заставляет вас использовать любой из них. могу ли я сделать вывод об использовании любого из них таким образом?
overxchange
@overexchange - 1) Я сказал "злоупотреблять", а не "использовать". 2) Кроме того, я не понимаю, о чем вы спрашиваете. Что вы имеете в виду под "предположить использование ..." ??? Код либо использует эти вещи, либо нет.
Stephen C
Я предполагаю, что использование instanceof& getClass()появляется из-за существующего плохого дизайна (неполиморфного) кода. я прав?
overxchange
5
@overexchange - нельзя утверждать, что любое использование instanceof(например) является плохим дизайном. Бывают ситуации, когда это может быть лучшим решением. То же самое для getClass(). Повторюсь, я сказал «злоупотреблять», а не «использовать» . Каждый случай необходимо рассматривать по существу ... а не слепо применяя какое-то необоснованное догматическое правило.
Stephen C
44

Вы хотите точно сопоставить класс , например, только сопоставление FileInputStreamвместо любого подкласса FileInputStream? Если да, используйте getClass()и ==. Я обычно делал это в a equals, чтобы экземпляр X не считался равным экземпляру подкласса X - иначе вы можете столкнуться с сложными проблемами симметрии. С другой стороны, это обычно более полезно для сравнения того, что два объекта относятся к одному классу, чем к одному конкретному классу.

В противном случае используйте instanceof. Обратите внимание, что getClass()вам нужно будет убедиться, что у вас есть ненулевая ссылка для начала, иначе вы получите NullPointerException, тогда как instanceofпросто вернетесь, falseесли первый операнд равен нулю.

Лично я бы сказал, что instanceofэто более идиоматично, но широкое использование любого из них в большинстве случаев является запахом дизайна.

Джон Скит
источник
18

Я знаю, что это было давно, но вчера я узнал альтернативу

Мы все знаем, что вы можете:

if(o instanceof String) {   // etc

но что, если вы не знаете, какой именно класс это должен быть? в целом вы не можете:

if(o instanceof <Class variable>.getClass()) {   

поскольку это дает ошибку компиляции.
Вместо этого есть альтернатива - isAssignableFrom ()

Например:

public static boolean isASubClass(Class classTypeWeWant, Object objectWeHave) {

    return classTypeWeWant.isAssignableFrom(objectWeHave.getClass())
}
Энди Дингфельдер
источник
8
Не используйте isAssignableFrom. Правильный способ записи o instanceof Stringс использованием отражения - String.getClass().isInstance(o). В документации javadoc даже сказано: этот метод является динамическим эквивалентом instanceofоператора языка Java .
Андреас
3

getClass () имеет ограничение, заключающееся в том, что объекты равны только другим объектам того же класса, того же типа времени выполнения, как показано в выводе кода ниже:

class ParentClass{
}
public class SubClass extends ParentClass{
    public static void main(String []args){
        ParentClass parentClassInstance = new ParentClass();
        SubClass subClassInstance = new SubClass();
        if(subClassInstance instanceof ParentClass){
            System.out.println("SubClass extends ParentClass. subClassInstance is instanceof ParentClass");
        }
        if(subClassInstance.getClass() != parentClassInstance.getClass()){
            System.out.println("Different getClass() return results with subClassInstance and parentClassInstance ");
        }
    }
}

Выходы:

SubClass расширяет ParentClass. subClassInstance - это instanceof ParentClass.

Различные методы getClass () возвращают результаты с subClassInstance и parentClassInstance.

Саурав Саху
источник