Является ли instanceof плохой практикой? Если да, то при каких обстоятельствах экземпляр еще предпочтительнее? - PullRequest
60 голосов
/ 01 мая 2010

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

Однако я вижу это здесь и там в библиотеках Java, так что я полагаю, что оно имеет свое место? При каких обстоятельствах это предпочтительнее? Это когда-нибудь неизбежно?

Ответы [ 7 ]

21 голосов
/ 01 мая 2010

Это определенно имеет место в стандартной реализации equals. Э.Г.

public boolean equals ( Object o )
{
  if ( this == o )
  {
     return true;
  }

  if ( ! (o instanceof MyClass) )
  {
    return false;
  }

  // Compare fields
  ...
}

Единственное, что нужно знать об instanceof, это то, что его LHS может быть null, и в этом случае выражение оценивается как false.

12 голосов
/ 01 мая 2010

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

Плохой практикой было бы иметь много instanceof с друг за другом, и в соответствии с ними вызывать разные методы объектов (конечно же, приведение). Это, вероятно, отражает то, что иерархия нуждается в переосмыслении и, возможно, рефакторинге.

11 голосов
/ 01 мая 2010

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

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

5 голосов
/ 01 мая 2010

Когда вы находитесь внутри чистой ОО-модели, тогда instanceof определенно является запахом кода.

Если, однако, вы не используете 100-процентную ОО-модель или вам нужно добавить в нее что-то изснаружи, тогда instanceof или эквиваленты (isXXX(), getType(), ...) могут иметь свое применение.

Общее «правило» состоит в том, чтобы по возможности избегать его, особенно когда вы контролирует иерархию типов и может использовать, например, полиморфизм подтипов.Идея состоит не в том, чтобы спросить объект, что это за тип и что-то с ним делать, а в том, чтобы напрямую или косвенно попросить объект через Visitor (по сути, двойной полиморфизм) выполнить какое-либо действие.

2 голосов
/ 02 мая 2010

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

Иногда это может вести себя так, как вы не ожидаете ... Что-то, что я когда-то случился:

Class B extends A
Class C extends A

B b = new B();
C c = new C();

b instanceof B -> true
b instanceof C -> true
c instanceof C -> true
c instanceof B -> true

(в моем случае это произошло из-за того, что hibernate создавал прокси-объекты .... но только в случае, когда код, добавляемый в instanceof, рискован)

1 голос
/ 01 мая 2010

Хорошо может использоваться как проверка работоспособности перед кастом; в дополнение к проверке того, что ваш объект имеет правильный тип, он также проверяет, что он не нулевой.

if (o instanceof MyThing) {
    ((MyThing) o).doSomething(); // This is now guaranteed to work.
} else {
    // Do something else, but don't crash onto ClassCast- or NullPointerException.
}
0 голосов
/ 08 ноября 2012

Как насчет создания фабрики? например,

public static Cage createCage(Animal animal) {
  if (animal instanceof Dog)
    return new DogHouse();
  else if (animal instanceof Lion)
    return new SteelCage();
  else if (animal instanceof Chicken)
    return new ChickenWiredCage();
  else if (animal instanceof AlienPreditor)
    return new ForceFieldCage();
  ...
  else
    return new GenericCage();
}
...