instanceof keyword usage

不想你离开。 提交于 2019-12-03 11:56:37

Generally speaking yes. It's best to keep all code that depends on being a specific class within that class, and using instanceof generally means that you've put some code outside that class.

Look at this very simple example:

public class Animal
{
}

public class Dog extends Animal
{
}

public class Cat extends Animal
{
}

public class SomeOtherClass
{
  public abstract String speak(Animal a)
  {
    String word = "";

    if (a instanceof Dog)
    {
      word = "woof";
    }
    else if (a instanceof Cat)
    {
      word = "miaow";
    }

    return word;
  }
}

Ideally, we'd like all of the behaviour that's specific to dogs to be contained in the Dog class, rather than spread around our program. We can change that by rewriting our program like this:

public abstract class Animal
{
  public String speak();
}

public class Dog extends Animal
{
  public String speak()
  {
    return "woof";
  }
}

public class Cat extends Animal
{
  public String speak()
  {
    return "miaow";
  }
}

public class SomeOtherClass
{
  public String speak(Animal a)
  {
    return a.speak();
  }
}

We've specified that an Animal has to have a speak method. Now SomeOtherClass doesn't need to know the particular details of each type of animal - it can hand that off to the subclass of Animal.

There are many good answers promoting virtual methods, but instanceof has its uses as well. Imagine that you iterate over List<Event>, to pick up all Urgent objects. You might do it using isUrgent() but I am not sure if it were necessarily more concise or readable. Also, isUrgent() would require making Event aware that its subclasses may possess the respective property, which might:

  • be regarded as something against modularity principles;
  • be even impossible, if Event belongs to some library that can not be modified.
  • Usage of instanceof is discouraged when same effect can be achieved via virtual methods, like in example of thomson_matt. However, it's necessary to use instanceof in some circumstances. For example, when your code gets Object from external source, say, network or third-party API which returns Object, and you must decide what is the type of this Object and act appropriately.

    Favor polymorphism and dynamic binding to downcasting and instanceof. This is the "OO Way" and enables you to write code that doesn't need to know about subtypes.

    EXAMPLE

    abstract class Animal {
        public abstract void talk();
        //...
    }
    
    class Dog extends Animal {
        public void talk() {
            System.out.println("Woof!");
        }
        //...
    }
    
    class Cat extends Animal {
        public void talk() {
            System.out.println("Meow!");
        }
        //...
    }
    
    class Hippopotamus extends Animal {
        public void talk() {
            System.out.println("Roar!");
        }
        //...
    }
    
    class Main {
    
        public static void main(String[] args) {
    
            makeItTalk(new Cat());
            makeItTalk(new Dog());
            makeItTalk(new Hippopotamus());
        }
    
        public static void makeItTalk(Animal animal) {
    
            animal.talk();
        }
    }
    

    The key is to not see instanceof as being part of common "normal practice". Like introspection in general, instanceof is a special tool for use in particular, atypical circumstances. Whenever you do use 'instanceof', you may also find yourself using other 'special' parts of the platform such as reflection more generally.

    So long as whenever you find yourself using it you accept that what you're doing is a kludge in the absence of a more elegant/practical alternative, then that's fine.

    That said, the most typical circumstances in everyday programs are probably:

    • implementing equals()
    • reading serialized objects
    • a few other cases where you're given an array/collection of items, e.g. enumerating JComponents in a frame/container and then taking action depending on type.

    A rule of thumb you could try and stick to is to not require users of a library to have to use 'instanceof', but rather have any cases of 'instanceof' internal to the library.

    Or put another way, you should re-frame your question: "What are the cases that 'intsanceof' is a workaround for?"

    It's discouraged because people might use it to do something like this:

    if( myAnimal instanceof Dog )
        ((Dog)myAnimal).bark();
    else( myAnimal instanceof Cat )
        ((Cat)myAnimal).meow();
    

    Instead, Animal should have a speak() method which Dog and Cat inherit. In proper OOP with polymorphism and dynamic binding, you would then simply do

    myAnimal.speak();
    

    However, there are some instances in which you must use instanceof to determine the specific type of an object. Perhaps you have a list of Animals in your house and the only ones you want to take out for a walk() are the Dogs. In that case you would iterate through your list and only walk() the dogs.

    How about in the case of a creation factory (See below)? In this case, I don't think it is appropriate for an Animal subclass to know how to build a cage for itself. It seems out of out of scope of what an Animal is and forces the Animal subclass to take on behaviors that are not intrinsic to what an Animal is.

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

    Another usage of instaceOf operation could be error handling. If you have similar error handling for exceptions, and you want to have it all in one place you can use:

    public void handleError(Throwable t, HttpServletRequest req) {
       if (t instaceOf ValidationException) {
                  ...doSomewthing......
       } else    if (t instaceOf DataException) {
                  ...doSomewthing......
       } else    if (t instaceOf DataException) {
                  ...doSomewthing......
       } else {
                  ...doSomewthing......
       }
    
    }
    

    with above code, you avoid to have many

    } catch <Exception> {
    

    blocks and instead have just one

    } catch (Throwable t) {
       handleError(t, request);
       return "errorPage" or whateveryouwant;
    }
    

    Also, one more thing is, is you check java source code, you will find so many usages of instaceof..

    And one good link: article about usage of instaceof

    标签
    易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
    该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!