Java中的多态性以及从这些类创建对象

时间:2013-04-28 21:03:27

标签: java variables inheritance methods polymorphism

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

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

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

Quad hero = new Hero();

Hero是Quad()的子类;

我的Hero课程中有变量,我无法访问。

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

Hero hero = new Hero();

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

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

考虑到这一点,何时使用我的原始方法是有用的:

Quad hero = new Hero();

那个人对我有意义,因为Hero也是四人组。我在Java代码示例中多次看到过这种类型的声明,并且我认为,但是最近的事件证明了这一点。

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

3 个答案:

答案 0 :(得分:4)

假设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

答案 1 :(得分:2)

将变量类型声明为Quad,意味着该变量还可以引用Quad的其他类型的子类,而不仅仅是Hero。如果您通过该参考,接收器将只知道它是某种四元组,并且不能依赖它是Hero。因此,它无法访问仅在子类中声明的引用字段。

至于何时使用这种赋值,我通常只在使用接口类型时才这样做。像:

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

但这只是一种习惯。

答案 2 :(得分:2)

如果将对象存储在Quad变量中,那么对于所有编译器都知道,存储在该变量中的对象是Quad,仅此而已。它可能是一个子类型,当然,但编译器不知道该子类型是什么。据它所知,该子类型将基本类型引入绝对零成员。如果编译器不能保证对象不是Quad,那么它不希望你做任何比允许你使用Quad更多的事情。< / p>

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

该语言允许您将对象强制转换为超类型的一个原因是,在许多情况下,您希望将该对象传递给不必了解基类的所有可能子类型的方法(例如, Hero)但只是传递的对象至少是基类(比如Quad)。另一种典型情况是,当您想要存储不是所有相同特定类型的各种对象时(它们不是全部Hero),但它们都有一个共同的祖先(它们都是Quad)和你想集体对待他们。通常,允许将对象强制转换为祖先类,因为在需要基类型的情况下使对象与其基类型兼容是有用的