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?

Ответ 1

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

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

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

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

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

(Есть исключения. Классический в реализации equals(Object), в котором вам нужно проверить тип аргумента и вернуть false, если он не соответствует. case, вам обычно нужно использовать getClass() для правильного выполнения контракта equals перед лицом подклассов.)

Ответ 2

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

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

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

Ответ 3

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

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

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())
}

Ответ 4

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 - экземпляр класса ParentClass.

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