【问题标题】:Polymorphism in Java and creating objects from these classesJava中的多态性和从这些类创建对象
【发布时间】:2013-04-28 21:03:26
【问题描述】:

当从这些类创建对象时,我对多态性和扩展类等在 Java 中的工作原理有点困惑。

我最近遇到了一个问题,这里有人帮我解决了(请参阅Not able to access object sub class's variable? (Java / Android))了解背景信息。

我试图创建一个像这样的对象:

Quad hero = new Hero();

Hero 是 Quad() 的子类;

我的 Hero 类中有我无法访问的变量。

解决方案是将我的对象创建更改为:

Hero hero = new Hero();

这样做,通过我的 hero 对象,我能够访问 Quad 和 Hero 类中的所有方法和变量。

我现在的问题是 - 为什么会这样?

考虑到这一点,什么时候使用我原来的方法有用:

Quad hero = new Hero();

这对我来说很有意义,因为 Hero 也是一个四边形。我在 Java 代码示例中多次看到这种类型的声明,并认为我理解,但最近的事件证明并非如此。

如果有人可以为我解释一下,将不胜感激 - 谢谢

【问题讨论】:

    标签: java variables inheritance methods polymorphism


    【解决方案1】:

    假设 OtherHero 也是 Quad 的子类,具有不同的行为:

    这样可以正常工作:

    Quad hero = new Hero();
    // some code
    hero = new OtherHero();
    

    而以下内容无法编译:

    Hero hero = new Hero();
    // some code
    hero = new OtherHero();
    

    这似乎没有用。现在假设你有一个方法,它有Quad 作为返回类型。我会用伪代码来写:

    Quad method() {
        if (condition)
            return new Hero();
        else
            return new OtherHero();
    }
    

    所以你实际上不知道它是否会返回 HeroOtherHero

    现在,你可以写:

    Quad foo = method();
    

    现在,您实际上不知道foo 的确切类型,但您可以将其用作Quad

    一个流行的例子是java.util.List

    你可以写:

    List<Integer> list = Arrays.asList(1,2,3,4,5,6);
    Collections.shuffle(list);
    

    List 是一个接口,由ArrayListLinkedList 和许多其他类实现。在不知道代码的情况下,我们不知道Arrays.asList()究竟返回了哪个类,但我们可以将其用作List

    【讨论】:

    • 嗯...有趣的@jlordo,谢谢。因此,例如,如果我有敌人1、敌人2、敌人3 和英雄,都创建为四边形,并且想将它们分组到数组中,那么我可以因为它们都是四边形吗?但是,我将如何访问仅存储在子类中的变量? (例如,Hero 子类中有一个变量存储在其中,而 Enemy 类没有。我如何访问这些变量,因为它们不在基类中?我无法通过对象访问它们,无需更改它是英雄的类型,但我不能将它与敌人分组?谢谢!!
    • @Zippy:这取决于你想如何访问这些变量,以及你想用它们做什么。如果您先检查instanceof 运算符,您可以安全地进行转换。我更喜欢创建一个Quad 接口(或抽象类)并且只使用它的方法。无论如何都应该封装变量,因此您可以通过类中的方法访问它们。
    • 谢谢@jlordo - 我可以请你编辑你的答案,给你上面评论的例子吗? (关于如何访问我在 cmets 中描述的变量?我通常发现通过示例更容易理解) - 然后我会阅读并标记你的答案 - 再次感谢,非常感谢!
    【解决方案2】:

    将变量类型声明为Quad,意味着该变量也可以引用Quad的其他类型的子类,而不仅仅是Hero。如果你传递那个引用,接收者只会知道它是“某种四边形”,不能依赖它是Hero。因此,它不能访问仅在子类中声明的引用字段。

    至于何时使用这种赋值,我通常只在使用接口类型时使用。喜欢:

    public List<SomeObject> doSomething() {
        List<SomeObject> result = new ArrayList<>();
        // do something
        return result;
    }
    

    但这真的只是一种习惯。

    【讨论】:

      【解决方案3】:

      如果您将对象存储在Quad 的变量中,那么就编译器所知,存储在该变量中的对象是Quad,仅此而已。当然,它可能是一个子类型,但编译器不知道那个子类型是什么。据它所知,该子类型将向基本类型引入绝对零个成员。如果编译器不能保证该对象不只是Quad,那么它就不会允许您做任何比Quad 允许您做的事情。

      当然,可以看到这个变量只被分配了一个new Hero()表达式。而且,当然,您可能知道特定变量将仅包含 Hero 类型的对象。但这是您可以在实践中推断出的运行时信息。编译器懒得计算所有这些场景。这就是为什么它有你。如果您知道存储在该变量中的对象将始终为Hero 类型,您可以继续将其表达给编译器。

      该语言允许您将对象转换为超类型的一个原因是,在许多情况下,您希望将该对象传递给不必知道基类的所有可能子类型的方法(例如, Hero),但只是传递的对象至少是一个基类(例如,Quad)。另一个典型的场景是,当您想要存储各种不同类型的对象时,这些对象并不都是相同的特定类型(它们不都是Hero),但它们都有一个共同的祖先(它们都是Quad)并且你想做与他们一起,集体。一般来说,允许将对象转换为祖先类,因为在需要基类型的情况下,使对象与其基类型兼容很有用

      【讨论】:

        猜你喜欢
        • 2015-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-25
        • 2012-05-09
        • 2016-05-03
        • 1970-01-01
        • 2020-12-01
        相关资源
        最近更新 更多