在从这些类创建对象时,我对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代码示例中多次看到过这种类型的声明,并且我认为,但是最近的事件证明了这一点。
如果有人能为我解释一下,我将不胜感激 - 谢谢
答案 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();
}
所以你实际上不知道它是否会返回Hero
或OtherHero
现在,你可以写:
Quad foo = method();
现在,您实际上并不知道foo
的确切类型,但您可以将其用作Quad
。
一个流行的例子是java.util.List
你可以写:
List<Integer> list = Arrays.asList(1,2,3,4,5,6);
Collections.shuffle(list);
List
是一个接口,由ArrayList
,LinkedList
和许多其他类实现。在不知道代码的情况下,我们不知道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
)和你想集体对待他们。通常,允许将对象强制转换为祖先类,因为在需要基类型的情况下使对象与其基类型兼容是有用的。