instanceof Vs 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/… .
Климент П

2
Ваш метод синхронізації спричиняє штучні затримки та призводить до неправильних результатів. Обміняйте порядок, яким ви виконуєте чеки, і ви побачите, що перша перевірка, яку ви робите (або ==, або екземпляр), буде завжди довшою. Я б здогадався, що це println () s. Ви ніколи не повинні включати цей матеріал у свій часовий блок.
kurtzmarc

Лише один коментар, для порівняння продуктивності, використовуйте ітерації декількох циклів (наприклад, 10000) для підвищення точності. Одне єдине виклик не є гарним заходом.
martins.tuga

Відповіді:


140

Причина того, що продуктивність instanceofта getClass() == ...інша різниця, полягає в тому, що вони роблять різні речі.

  • instanceofперевіряє, чи посилання на об'єкт ліворуч (LHS) є екземпляром типу з правого боку (RHS) або деяким підтипом .

  • getClass() == ... перевіряє, чи типи ідентичні.

Тож рекомендація - ігнорувати питання про продуктивність та використовувати альтернативу, яка дає відповідь, який вам потрібен.

Чи використання instanceOfоператора поганою практикою?

Не обов'язково. Надмірне використання instanceOfабо getClass() може бути "дизайнерським запахом". Якщо ви не обережні, ви закінчите дизайн, де додавання нових підкласів призводить до значної кількості переробки коду. У більшості ситуацій кращим підходом є використання поліморфізму.

Однак є випадки, коли це НЕ "дизайнерський запах". Наприклад, equals(Object)вам потрібно перевірити фактичний тип аргументу та повернути falseйого, якщо він не відповідає. Це найкраще робити за допомогою getClass().


Такі терміни, як "найкраща практика", "погана практика", "дизайнерський запах", "антипаттерн" і так далі, слід вживати сумлінно і ставитися до них з підозрою. Вони спонукають до чорно-білого мислення. Краще робити свої судження в контексті, а не грунтуватися виключно на догмі; наприклад, те, що хтось сказав, є "найкращою практикою".


@StephenC Як ви вже говорили, це code smellвикористовувати будь-яке. Це означає, що це наслідок поганого дизайнерського (не поліморфного) коду, який змушує вас використовувати будь-який. Чи можу я зробити висновок про використання будь-якого з них таким чином?
переобмін

@overexchange - 1) Я сказав "надмірне використання" не "використання". 2) Крім того, я не розумію, про що ви питаєте. Що ви маєте на увазі під "підсумком використання ..." ??? Код або використовує ці речі, або його немає.
Стівен C

Я роблю це, використання instanceof& getClass()входить в картину через існуючий поганий дизайн (не поліморфний) коду. я прав?
переобмін

5
@overexchange - Ви не можете дійсно зробити висновок про те, що використання instanceof(наприклад) поганого дизайну. Бувають ситуації, коли це може бути найкращим рішенням. Те саме для getClass(). Повторюся, що я сказав «перестарайтеся», а не «використовуйте» . Кожен випадок потрібно оцінювати по суті ... а не сліпо застосовувати якесь необґрунтоване догматичне правило.
Stephen C

44

Ви хочете точно відповідати класу , наприклад, лише відповідність FileInputStreamзамість будь-якого підкласуFileInputStream ? Якщо так, використовуйте getClass()і ==. Як правило, це робиться в 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). Явадок навіть говорить так: Цей метод є динамічним еквівалентом 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 ");
        }
    }
}

Виходи:

Підклас розширює ParentClass. subClassInstance - це примірник ParentClass.

Різні getClass () повертають результати з subClassInstance та parentClassInstance.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.