关于多态性的使用的疑问,以及关于多态如何与铸造有关?

sfr*_*frj 6 java oop polymorphism instanceof

我向在大学学习这门课程的学生讲授Java编程语言的基础知识.

今天其中一个让我对她的问题感到困惑,所以我告诉她给我一天的时间来思考这个问题,我会尽可能准确地给她答案.

她告诉我,当她instanceof在考试中使用关键词时,老师非常生气.

此外,她说老师说没有办法证明如果使用这个词,多态性是如何起作用的.

我想了很多,试图找到一种方法来证明在某些情况下我们需要使用instanceof,而且即使我们使用它,在这种方法中仍然存在一些多态性.

所以这是我做的例子:

public interface Animal
{
    public void talk();
}

class Dog implements Animal {        
    public void talk() {
        System.out.println("Woof!");
    }
}

public class Cat implements Animal
{
    public void talk() {
         System.out.println("Meow!");
    }    

    public void climbToATree() {
          System.out.println("Hop, the cat just cimbed to the tree");
    }
}

class Hippopotamus implements Animal {
    public void talk() {
        System.out.println("Roar!");
    }    
}

public class Main {
    public static void main(String[] args) {
        //APPROACH 1
        makeItTalk(new Cat());
        makeItTalk(new Dog());
        makeItTalk(new Hippopotamus());

       //APPROACH 2
        makeItClimbToATree(new Cat());
        makeItClimbToATree(new Hippopotamus());
    }

    public static void makeItTalk(Animal animal) {
        animal.talk();
    }

   public static void makeItClimbToATree(Animal animal) {
       if(animal instanceof Cat) {
            ((Cat)animal).climbToATree();                  
       }
       else {
           System.err.println("That animal cannot climb to a tree");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的结论如下:

  • 第一种方法(APPROACH 1)是如何编程到接口而不是实现的简单演示.我认为多态性在方法的参数中makeItTalk(Animal animal)以及通过使用动物对象调用方法谈话的方式清晰可见.(这部分没问题)

  • 第二部分让我感到困惑.她instanceof在考试的某个时候使用过(我不知道他们的考试是怎么样的),并且由于老师说,你没有证明多态性,因此没有被正确接受.

为了帮助她了解何时可以使用instanceof,我想告诉她,当她需要调用的方法不在界面中时,她可以使用它,但它只是在其中一个实现类中.

正如你所看到的,只有猫可以爬到树上,将河马或狗爬到树上是不合逻辑的.我认为这可能是何时使用的一个例子instanceof

  • 但是方法2中的多态性呢?

  • 你在那里看到多态的多少用途(只有方法2)?

  • 你认为这一行有多种类型的多态性吗?

    ((Cat)animal).climbToATree();

我认为确实如此,因为为了实现这种类型的Casting,对象需要具有IS-A关系,这在某种程度上是多态的.

  • 你怎么想,这是对的吗?

  • 如果是的话,你会用自己的话来解释,铸造依赖于多态?

irc*_*ell 5

instanceof方法被视为坏的原因很简单.猫不是唯一Animal可以爬树的人.

如果在路上需要添加考拉类,会发生什么.然后你的简单if就变得不那么简单了or.那么,当你添加另一个类时会发生什么?还有一个.而另一个.这instanceof是被视为糟糕的主要原因.因为它将实现耦合到具体类,而不是为被调用者打开它来确定要做什么.

只需实施该makeItClimbToATree()方法即可CantClimbTreesException对无法攀​​爬的动物进行调用.这样你就可以拥有两全其美.易于实施,易于扩展.

恕我直言,instanceof只有一个真正有效的用途:在一个测试用例中,从一个方法测试返回的实例匹配预期的返回类型(在非类型安全的语言中).

基本上任何其他用途都可能被重构或设计不同以消除其使用的需要.

查看它的另一种方法是:多态性允许您从代码中消除几乎所有条件语句.您无法摆脱的唯一条件(至少所有条件)都在对象创建方法中(例如在必须根据运行时参数选择类的工厂中).几乎任何其他条件都可以被多态性取代.因此,任何执行条件执行的东西都是反多态的.这并不是说它很糟糕(Good和Good Enough之间存在巨大差异),但在学术讨论中,它并不是多态的......

永远不要忘记60/60规则.总开发时间的60%将用于维护您编写的代码,并且60%的时间将用于添加新功能.让维护更轻松,您的生活也会更轻松.这就是为什么instanceof不好.它使初始设计更容易,但使长期维护变得复杂(无论如何更昂贵)......


use*_*own 4

在上面的示例中,无需调用

makeItClimbToATree (new Hippopotamus ());
Run Code Online (Sandbox Code Playgroud)

如果 makeItClimbToATree 期望的不是动物,而是更具体的东西,即真正能够爬树的东西,那么它可以很容易地避免。允许动物的必要性,以及因此使用instanceof的必要性,是不可见的。如果你用动物列表来管理动物,那就更明显了。

虽然 ircmaxell 的解释开头很好,但在介绍考拉和其他爬树者时,他没有看到隐藏在海葵中的第二个扩展:动物的不同能力,如海葵隐藏者、冬眠、蓝眼、吃虫等等,等等。您最终会得到布尔值超过布尔值,不断重新编译基类,以及破坏扩展客户类,这将需要再次重新编译,并且无法以类似的方式引入它们自己的可能性。

客户 A 需要客户 B 声明 NotBugEatingException,以将您的行为放入基类中。

引入您自己的接口,并与instanceof 相结合,是一种更简洁的方法,也更灵活。客户 A 可能定义了潜水LikeAPenguin,而客户 B 则大肆宣扬,两者互不了解,既不会影响 Animal 类,也不会引发无用的重新编译。

import java.util.*;

interface Animal {
    public void talk ();
}

interface TreeClimbing {
    public void climbToATree ();
}

class Dog implements Animal {
    public void talk () { System.out.println("Woof!"); }
}

class Cat implements Animal, TreeClimbing {
    public void talk () { System.out.println("Meow!"); }    
    public void climbToATree () { System.out.println ("on top!"); }
}

public class TreeCriterion {

    public static void main(String[] args) {
        List <Animal> animals = new ArrayList <Animal> ();
        animals.add (new Cat ());
        animals.add (new Dog ());

        discuss (animals);
        upTheTree (animals);
    }

    public static void discuss (List <Animal> animals) {
        for (Animal a : animals)
            a.talk ();
    }

    public static void upTheTree (List <Animal> animals) {
        for (Animal a : animals) {
            if (a instanceof TreeClimbing)
                ((TreeClimbing) a).climbToATree ();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我们不需要第三种动物,狗和猫就足够了。我将它们设置为默认可见而不是公开,以使整个示例适合单个文件。