简体   繁体   English

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

[英]Polymorphism in Java and creating objects from these classes

I'm a little confused exactly about how polymorphism and extending classes etc... works in Java when creating objects from these classes. 在从这些类创建对象时,我对Java的多态性和扩展类等的工作方式有点困惑。

I recently had a problem which someone on here helped me resolved (see Not able to access object sub class's variable? (Java / Android) ) for background. 我最近有一个问题,有人在这里帮助我解决(请参阅无法访问对象子类的变量?(Java / Android) )for background。

I was attempting to create an object like so: 我试图像这样创建一个对象:

Quad hero = new Hero();

Where Hero was a subclass of Quad(); Hero是Quad()的子类;

I had variables in my Hero class which I wasn't above to access. 我的Hero课程中有变量,我不在上面访问。

The solution was to change my object creation to: 解决方案是将我的对象创建更改为:

Hero hero = new Hero();

doing this, through my hero object, I was able to access all methods and variables in both my Quad and Hero classes. 这样做,通过我的英雄对象,我能够访问我的Quad和Hero类中的所有方法和变量。

My question now is - Why is this? 我现在的问题是 - 这是为什么?

And with this in mind, when would it be useful to use my original method: 考虑到这一点,何时使用我的原始方法是有用的:

Quad hero = new Hero();

That one makes sense to me as Hero is also a quad. 那个人对我有意义,因为Hero也是四人组合。 I've seen this type of declaration many times in Java code examples, and thought I understood, it but recent events have proved otherwise. 我在Java代码示例中多次看到过这种类型的声明,并且我认为,但是最近的事件证明了这一点。

Would be grateful if someone could explain this for me - thanks 如果有人能为我解释这一点,将不胜感激 - 谢谢

Assume OtherHero is also a subclass from Quad with different behaviour: 假设OtherHero也是Quad的子类,具有不同的行为:

This will work fine: 这样可以正常工作:

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

Whereas the following won't compile: 以下不会编译:

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

This doesn't seem to be useful. 这似乎没有用。 Now assume you have a method, that has Quad as return type. 现在假设你有一个方法,它有Quad作为返回类型。 I'll write it in pseudocode: 我会用伪代码写它:

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

So you actually don't know if it will return a Hero or an OtherHero 所以你实际上不知道它是否会返回HeroOtherHero

Now, you can write: 现在,你可以写:

Quad foo = method();

Now, you actually don't know the exact type of foo , but you can use it as Quad . 现在,您实际上并不知道foo的确切类型,但您可以将其用作Quad

A popular example is java.util.List 一个流行的例子是java.util.List

You can write: 你可以写:

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

List is an interface, implemented by ArrayList , LinkedList and many other classes. List是一个接口,由ArrayListLinkedList和许多其他类实现。 Without knowing the code, we don't know which class exactly is returned by Arrays.asList() , but we can use it as a List . 在不知道代码的情况下,我们不知道Arrays.asList()确切返回了哪个类,但我们可以将它用作List

Declaring the variable type as Quad , means that the variable also can reference other types of subclasses of Quad , not only Hero . 将变量类型声明为Quad ,意味着变量也可以引用Quad其他类型的子类,而不仅仅是Hero And if you pass that reference around, the receiver would only know that it is "some kind of quad", and can't rely on it being a Hero . 如果你传递那个参考,接收器只会知道它是“某种四边形”,并且不能依赖它作为Hero Hence, it can not access the fields of the reference that are declared only in the subclass. 因此,它无法访问仅在子类中声明的引用字段。

As for when to use that kind of assignment, I usually only do it when working with interface types. 至于何时使用这种赋值,我通常只在使用接口类型时才这样做。 Like: 喜欢:

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

But it's really just a habit. 但这真的只是一种习惯。

If you store your object in a variable of Quad then, for all the compiler knows, the object stored in that variable is a Quad and nothing more. 如果将对象存储在Quad的变量中,那么对于所有编译器都知道,存储在该变量中的对象是Quad ,仅此而已。 It may be of a subtype, sure, but the compiler has no idea what that subtype is. 它可能是一个子类型,当然,但编译器不知道该子类型是什么。 For all it knows, that subtype will be introducing absolutely zero members to the base type. 据它所知,该子类型将基本类型引入绝对零成员。 If the compiler has no guarantee that the object is anything more than a Quad , then it doesn't want to allow you to do anything more than what it would allow you to do with a Quad . 如果编译器不能保证对象不是Quad ,那么它不希望你做任何比使用Quad更多的事情。

Granted, you can see that this variable is only ever assigned a new Hero() expression. 当然, 可以看到这个变量只被分配了一个new Hero()表达式。 And, granted, you may know that a specific variable will only hold objects of the Hero type. 并且,您可能知道特定变量只能保存Hero类型的对象。 But this is runtime information that you can deduce in practice. 但这是您可以在实践中推断出的运行时信息。 The compiler can't bother to calculate all these scenarios. 编译器无法计算所有这些场景。 That's why it has you. 这就是为什么它有你。 If you know that objects stored in that variable will always be of type Hero , you can go on and express it to the compiler. 如果您知道存储在该变量中的对象将始终是Hero类型,您可以继续将其表达给编译器。

One reason the language allows you to cast an object to a super type is because in many occasions you want to pass that object to a method that doesn't have to know about all the possible subtypes of the base class (say, Hero ) but only that the passed object is at least of a base class (say, Quad ). 语言允许您将对象强制转换为超类型的一个原因是因为在很多情况下您希望将该对象传递给一个方法,该方法不必了解基类的所有可能的子类型(例如, Hero ),只是传递的对象至少是一个基类(比方说, Quad )。 Another typical scenario is when you want to store various objects that are not all of the same specific type (they are not all Hero ), but they all have a common ancestor (they are all Quad ) and you want to do something with them, collectively. 另一个典型的场景是当你想要存储不是所有相同特定类型的各种对象时(它们都不是Hero ),但是它们都有一个共同的祖先(它们都是Quad )并且你想用它们做一些事情,统称。 In general, then, casting objects to an ancestor class is permitted because it is useful to make objects compatible with their base type in situations where that base type is required . 通常,允许将对象转换为祖先类,因为在需要该基类型的情况下使对象与其基类型兼容是有用的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM