Перейти к содержимому

В чем разница между instanceof и getclass

  • автор:

Java getClass или instanceof для equals

Что лучше использовать для сравнения типов классов у переменных при написании equals ? Я уже описывал этот метод в специальной статье. С одной стороны, я часто видел использование instanceof :

class MyObject < private String field ; public String getField ( ) < return field ; public void setField ( String field ) < this . field = field ; public boolean equals ( final Object other ) < if ( ! ( other instanceof MyObject ) ) < return false ; MyObject castOther = ( MyObject ) other ; return Objects . equals ( field , castOther . field ) ; public int hashCode ( ) < return Objects . hash ( field ) ;

На первый взгляд, здесь всё впорядке. Но давайте создадим дочерний класс:

class MyChildObject extends MyObject < private boolean v1 ; public boolean isV1 ( ) < public void setV1 ( boolean v1 ) < this . v1 = v1 ; public boolean equals ( final Object other ) < if ( ! ( other instanceof MyChildObject ) ) < return false ; MyChildObject castOther = ( MyChildObject ) other ; return Objects . equals ( v1 , castOther . v1 ) ; public int hashCode ( ) < return Objects . hash ( v1 ) ;

Вроде тоже ничего плохого. Но давайте проведём следующий эксперимент:

my.equals(child) = true
child.equals(my) = false

Но в договорённости о работе equals в официальном JavaDoc сказано, что метод должен быть симметричным. Симметричность означает, что для каждой пары x и y у которой x . equals ( y ) должно быть равно y . equals ( x ) . Значит, наши методы некорректны. Перепишем их на getClass :

class MyObject < public boolean equals ( final Object other ) < if ( other == null ) < return false ; if ( ! getClass ( ) . equals ( other . getClass ( ) ) ) < return false ; MyObject castOther = ( MyObject ) other ; return Objects . equals ( field , castOther . field ) ; class MyChildObject < public boolean equals ( final Object other ) < if ( other == null ) < return false ; if ( ! getClass ( ) . equals ( other . getClass ( ) ) ) < return false ; MyChildObject castOther = ( MyChildObject ) other ; return Objects . equals ( v1 , castOther . v1 ) ; public int hashCode ( ) < return Objects . hash ( v1 ) ;

Проведём эксперимент ещё раз:

my.equals(child) = false
child.equals(my) = false

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

Вывод: Для equals всегда нужно сравнивать типы объектов через getClass.

Все методы equals и hashCode для данной статьи были сгенерированы с помощью плагина Jenerate для Eclipse.

Опубликовано 05.08.2019 05.08.2019 Автор Урванов Фёдор Рубрики Java Метки Java

Java getClass или instanceof для equals: 3 комментария

Аноним :
equals не всегда симметричен.
в той же HashMap это не так.
Аноним :

А что, если наш объект — энтити хибернейт? getClass у такого объекта укажет нам на прокси и мы не сможем добраться до сравнения полей объекта.

Урванов Фёдор :

Ну да, возможно, для Hibernate это не всегда подходит, хотя и тоже спорно. Но требование по симметричности вообще было в самой документации от Oracle, поэтому я его здесь привёл.

Различия между instanceof и Class.isAssignableFrom(…)

Когда речь заходит о проверке принадлежности объекта к определенному классу или интерфейсу в Java, можно использовать два метода: instanceof и Class.isAssignableFrom(…).

Алексей Кодов
Автор статьи
10 июля 2023 в 16:42

Когда речь заходит о проверке принадлежности объекта к определенному классу или интерфейсу в Java, можно использовать два метода: instanceof и Class.isAssignableFrom(. ) . Оба этих оператора используются для определения того, является ли объект экземпляром определенного класса или интерфейса. Но в чем же разница между ними?

Возьмем для примера следующий код:

Object a = new String("example"); boolean result = a instanceof String;
Object a = new String("example"); boolean result = String.class.isAssignableFrom(a.getClass());

В обоих случаях результат будет true , поскольку a действительно является экземпляром класса String .

Однако существуют различия в поведении этих двух операторов. Главное различие заключается в том, как они обрабатывают null значения.

Оператор instanceof возвращает false , если его левый операнд null . Это означает, что следующий код:

Object a = null; boolean result = a instanceof String;

вернет false , поскольку a равно null .

С другой стороны, метод Class.isAssignableFrom(. ) выбросит исключение NullPointerException , если ему передать null значение. Таким образом, следующий код:

Object a = null; boolean result = String.class.isAssignableFrom(a.getClass());

выбросит исключение NullPointerException , поскольку a.getClass() возвращает null .

Таким образом, в то время как instanceof безопасен для использования с null значениями, Class.isAssignableFrom(. ) требует предварительной проверки на null для избежания исключений. Это основное различие между instanceof и Class.isAssignableFrom(. ) .

instanceof Vs getClass( )

Is there any guideline, which one to use getClass() or instanceOf ? Given a scenario: I know exact classes to be matched, that is String , Integer (these are final classes), etc. Is using instanceOf operator bad practise ?

15.6k 34 34 gold badges 115 115 silver badges 200 200 bronze badges
asked Feb 14, 2011 at 7:40
3,935 2 2 gold badges 31 31 silver badges 45 45 bronze badges
This is explained in: stackoverflow.com/questions/596462/….
Feb 14, 2011 at 7:43

Your timing method is causing artificial delays and producing incorrect timing results. Swap the order you do the checks and you’ll see the first check you do (either == or instanceof) will always be longer. I’d guess it’s the println()s. You should never include that stuff in your timing block.

Sep 14, 2012 at 18:30

Just one comment apart, to compare performance, use multiple cycle iterations (e.g. 10000) in order to improve accuracy. One single invocation is not a good measure.

Mar 18, 2014 at 10:28
How large is the difference?
Dec 16, 2020 at 14:30

4 Answers 4

The reason that the performance of instanceof and getClass() == . is different is that they are doing different things.

  • instanceof tests whether the object reference on the left-hand side (LHS) is an instance of the type on the right-hand side (RHS) or some subtype.
  • getClass() == . tests whether the types are identical.

So the recommendation is to ignore the performance issue and use the alternative that gives you the answer that you need.

Is using the instanceOf operator bad practice ?

Not necessarily. Overuse of either instanceOf or getClass() may be «design smell». If you are not careful, you end up with a design where the addition of new subclasses results in a significant amount of code reworking. In most situations, the preferred approach is to use polymorphism.

However, there are cases where these are NOT «design smell». For example, in equals(Object) you need to test the actual type of the argument, and return false if it doesn’t match. This is best done using getClass() .

Terms like «best practice», «bad practice», «design smell», «antipattern» and so on should be used sparingly and treated with suspicion. They encourage black-or-white thinking. It is better to make your judgements in context, rather than based purely on dogma; e.g. something that someone said is «best practice». I recommend that everyone read No Best Practices if they haven’t already done so.

Оператор instanceof

Java-университет

Оператор instanceof - 1

Используя оператор instanceof , можно узнать, от какого класса произошел объект. Этот оператор имеет два аргумента. Слева указывается ссылка на объект, а справа — имя типа, на совместимость с которым проверяется объект. Например:

 Parent р = new Child(); // проверяем переменную р типа Parent //на совместимость с типом Child print(p instanceof Child); 

Результатом будет true. Таким образом, оператор instanceof опирается не на тип ссылки, а на свойства объекта, на который она ссылается. Но этот оператор возвращает истинное значение не только для того типа, от которого был порожден объект. Добавим к уже объявленным классам еще один:

 // Объявляем новый класс и наследуем // его от класса Child class ChildOfChild extends Child <> 

Теперь заведем переменную нового типа:

 Parent p = new ChildOfChild(); print(p instanceof Child); 

В первой строке объявляется переменная типа Parent , которая инициализируется ссылкой на объект, порожденный от ChildOfChild . Во второй строке оператор instanceof анализирует совместимость ссылки типа Parent с классом Child , причем задействованный объект не порожден ни от первого, ни от второго класса. Тем не менее, оператор вернет true, поскольку класс, от которого этот объект порожден, наследуется от Child . Ссылка на первоисточник: Operator instanceof

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *