it-swarm-ru.tech

instanceof Vs getClass ()

Я вижу увеличение производительности при использовании оператора 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 плохой практикой?

102
blob

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

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

  • getClass() == ... проверяет, идентичны ли типы.

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

И да, чрезмерное использование любого из них может быть "дизайнерским запахом". Если вы не будете осторожны, вы получите схему, в которой добавление новых подклассов приводит к значительной переработке кода. В большинстве ситуаций предпочтительным подходом является использование полиморфизма.

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

128
Stephen C

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

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

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

38
Jon Skeet

Я знаю, что прошло много времени с тех пор, как об этом спросили, но я узнал альтернативу вчера

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

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())
}
17
Andy Dingfelder

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 ");
        }
    }
}

Результаты:

Подкласс расширяет ParentClass. subClassInstance является экземпляром ParentClass.

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

2
Saurav Sahu