java java中的多态性:为什么我们要设置对子对象的父引用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32142128/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Polymorphism in java: Why do we set parent reference to child object?
提问by Subhadeep Banerjee
I want to understand the use-case of setting a parent reference to a child object. Example: Dog class extends Animal class. (No interfaces, mind it) I would normally create an object of Dog like this:
我想了解设置对子对象的父引用的用例。示例:Dog 类扩展了 Animal 类。(没有接口,请注意)我通常会像这样创建一个 Dog 对象:
Dog obj = new Dog();
Now, since Dog is a subclass of Animal it already has access to all of Animal's methods and variables. Then, what difference does this make:
现在,由于 Dog 是 Animal 的子类,它已经可以访问 Animal 的所有方法和变量。那么,这有什么区别:
Animal obj = new Dog();
Please provide a proper use-case with an code snippet of it's use. No theoretical articles about 'Polymorphism' or 'Coding to interfaces' please!
请提供正确的用例及其使用的代码片段。请不要关于“多态”或“接口编码”的理论文章!
Code:
代码:
public class Polymorphism {
public static void main(String[] args){
Animal obj1 = new Dog();
Dog obj2 = new Dog();
obj1.shout(); //output is bark..
obj2.shout(); //output is bark..
}
}
class Animal{
public void shout(){
System.out.println("Parent animal's shout");
}
}
class Dog extends Animal{
public void shout(){
System.out.println("bark..");
}
}
class Lion extends Animal{
public void shout(){
System.out.println("roar..");
}
}
class Horse extends Animal{
public void shout(){
System.out.println("neigh");
}
}
Output is the same for both the cases. Then why do we set parent reference to child object?
两种情况的输出相同。那为什么我们要设置父对象对子对象的引用呢?
采纳答案by Subhadeep Banerjee
Okay. I think I got my answer.
好的。我想我得到了答案。
public class Polymorphism {
public static void main(String[] args){
Animal obj1 = new Horse();
Horse obj2 = new Horse();
obj1.shout(); //output is neigh..
obj2.shout(); //output is neigh..
obj1.winRaces(); /*But this is not allowed and throws compile time error,
even though the object is of Animal type.*/
}
}
class Animal{
public void shout(){
System.out.println("Parent animal's shout");
}
}
class Horse extends Animal{
public void shout(){
System.out.println("neigh..");
}
public void winRaces(){
System.out.println("won race..");
}
}
So, when we use parent reference for child class object, we cannot access any specific methods in child class (that are not present in parent class) using that object.
因此,当我们对子类对象使用父引用时,我们无法使用该对象访问子类中的任何特定方法(父类中不存在的方法)。
回答by Suresh Atta
Let me code some time.
让我花点时间码字。
List<String> list = new ArrayList<String>;
list.doThis();
list.doThat();
Oh wait ..I'm gone mad. I want to use LinkedList
instead of ArrayList
哦等等..我疯了。我想用LinkedList
而不是ArrayList
List<String> list = new LinkedList<String>;
list.doThis();
list.doThat();
Yup, I have to change only declaration part. No need to touch all of my code. Thanks to programming to interfaces and with super classes.
是的,我只需要更改声明部分。无需触及我的所有代码。感谢编程接口和超类。
回答by Raghavendra
Think generally, you will know java casting/oop concept.
一般来说,你会知道java cast/oop的概念。
Dog
is a type of Animal
so you can assign it to an animal.
Dog
是一种类型,Animal
因此您可以将其分配给动物。
But you can't assign Animal
to a Dog
. Because it can be any other animal like Cat
. If you are sure the object is Dog
, you can caste that to Animal
. If the Animal
is of type Dog
then you cannot magically cast to a Goat
.
但是您不能分配Animal
给Dog
. 因为它可以是任何其他动物Cat
。如果您确定该对象是 Dog
,则可以将其强制转换为Animal
。如果Animal
is 是类型,Dog
那么你不能神奇地转换为 a Goat
。
回答by MD Sayem Ahmed
This is an implementation of a principle which says -
这是一个原则的实现,它说——
Program to an interface, not to an implementation.
编程到接口,而不是实现。
As an example, if you design a method to accept a reference of type Animal
, then in future you can easily pass an= Cat
implementation to it (provided of course that the Cat
is a sub-type of Animal
.
例如,如果您设计一个方法来接受 type 的引用Animal
,那么将来您可以轻松地将 an=Cat
实现传递给它(当然前提Cat
是 是Animal
.
Which means -
意思是 -
public void doSomethingWithAnimal(Animal animal) {
// perform some action with/on animal
}
is much more flexible than -
比 - 灵活得多
public void doSomethingWithAnimal(Dog d) {
// your code
}
because for the first method, you can easily do something like -
因为对于第一种方法,您可以轻松地执行以下操作 -
doSomethingWithAnimal(new Cat());
if you ever decide to create new Cat
type, inheriting from Animal
.
如果您决定创建新Cat
类型,继承自Animal
.
回答by Marco13
Although there are some good answers (among the "meh" ones), it seems like none was acceptable for you. Maybe they are too theoretical or contain details that you are not interested in. So another try:
尽管有一些很好的答案(在“meh”中),但似乎没有一个是您可以接受的。也许它们太理论化或包含您不感兴趣的细节。所以再试一次:
For the example that you described, it does not matter. If you really only have a two-line method like
对于您描述的示例,这无关紧要。如果你真的只有一个两行的方法,比如
void doit()
{
Animal x = new Dog();
x.shout();
}
then you could also have written
那么你也可以写
void doit()
{
Dog x = new Dog();
x.shout();
}
and this would nothave a direct disadvantage.
这不会有直接的缺点。
One could even generalize this statement: For a reference that is only used locally, it does not matter. When you declarethe reference in the method, and onlyuse this reference in this method, and do notpass it to other methods, then there is no direct advantage in declaring it as Animal
instead of as Dog
. You can to both.
甚至可以概括这种说法:对于仅在本地使用的参考,这无关紧要。当你在方法中声明了引用,并且只在这个方法中使用了这个引用,并且没有将它传递给其他方法时,那么声明它为 asAnimal
而不是 as并没有直接的优势Dog
。你可以两者兼而有之。
But...
但...
even if you are not interested in this, I can't omit it:
即使你对此不感兴趣,我也不能省略它:
... using the parent type is part of a best practice:
...使用父类型是最佳实践的一部分:
You should always use the least specific type that is sufficient for what you want to do
您应该始终使用足以完成您想要做的事情的最不具体的类型
This has various technical reasons, regarding abstraction, generalization, flexibility, the application of polymorphism, and one could even go so far to call it a sort of "type hygiene".
这有各种各样的技术原因,关于抽象、泛化、灵活性、多态性的应用,甚至可以说它是一种“类型卫生”。
And this explicitly alsorefers to the case where the reference is only used locally: If you don't want to call methods that are specific for the type Dog
, but only want to call methods from the Animal
class, then you should make this clear by declaring the variable as an Animal
- simply because that's the least specific type that you need. So there is an indirectadvantage of using the type Animal
in these cases - namely that it is clear that the following code will only use methods of the Animal
class, and noneof the Dog
class.
并且这明确也指引用仅在本地使用的情况:如果您不想调用特定于 type 的方法Dog
,而只想调用Animal
类中的方法,那么您应该通过声明来明确这一点变量作为Animal
- 只是因为这是您需要的最不具体的类型。所以在这些情况下使用类型有一个间接的优势Animal
- 即很明显,下面的代码将只使用Animal
类的方法,而不使用Dog
类的方法。
One could continue and go very far with further justifications, use case examples and technical details here. But for this, you may refer to the other answers, or some intermediate or advanced texbooks and tutorials.
人们可以继续并在此处进一步论证、用例示例和技术细节。但是为此,您可以参考其他答案,或者一些中级或高级教科书和教程。
回答by Marko Topolnik
When you start with such a simple example, you can't see any benefits because you have tightly coupled the variable to the actual type of object it will hold.
当您从这样一个简单的示例开始时,您看不到任何好处,因为您已将变量与它将保存的实际对象类型紧密耦合。
Polymorphism comes into its own only when you consider method declarations where the parameter is of the least specific type needed by the method's implementation: then you can call it with any subtype and the method will know what to do with it, even though it has no knowledge of the actual object type. That's the essence of Liskov substitutability of types.
仅当您考虑方法声明中的参数是方法实现所需的最不特定类型的方法声明时,多态性才会发挥作用:然后您可以使用任何子类型调用它,并且该方法将知道如何处理它,即使它没有实际对象类型的知识。这就是类型的 Liskov 可替代性的本质。
So imagine you have a method
所以想象你有一个方法
int getAge(Animal a) {
return Days.toYears(currentDate() - a.dateOfBirth());
}
The method will work against any Animal
, even those you defined after defining the method.
该方法将适用于任何Animal
,甚至是您在定义方法后定义的那些。
But, if you happen to understand the above, yet ask specificallywhy one would write
但是,如果您碰巧理解了上述内容,请具体询问为什么要写
Animal a = new Dog();
then it still often makes sense: you promise up-front that you won't refer to any dog-specific aspects of the instance. Typically you'll see
那么它通常仍然是有道理的:您预先承诺不会提及实例的任何特定于狗的方面。通常你会看到
List<String> strings = new ArrayList<>();
and in this case we know that the rest of the code doesn't rely on the specific choice of ArrayList
as list implementation. This is a much smaller difference than the one decribed above, but it's a combination of brevity, safety, and custom which makes it stick.
在这种情况下,我们知道其余代码不依赖于ArrayList
as 列表实现的特定选择。这比上面描述的差异要小得多,但它结合了简洁、安全和定制,使其得以坚持。
回答by Thom
This would be when you want the code that you're writing to work against the Animal interface instead of the Dog implementation. Creating an object in this way makes your code more robust in the long term.
这将是当您希望您正在编写的代码针对 Animal 接口而不是 Dog 实现工作时。从长远来看,以这种方式创建对象会使您的代码更加健壮。
I frequently use:
我经常使用:
List<Object> aList = new ArrayList<>();
This is important when defining class level variables, because you want your whole object to work even if you change an unimportant detail later.
这在定义类级别变量时很重要,因为即使稍后更改不重要的细节,您也希望整个对象都能工作。
回答by Goyal Vicky
Looking at the question:-
看问题:-
Polymorphism in java: Why do we set parent reference to child object?
In a method like below(Factory Pattern):-
在如下方法中(工厂模式):-
public Animal doSomething(String str){
if(str.equals("dog")){
return new Dog();
}
else if(str.equals("cat")){
return new Cat();
}
else {
return new Animal();
}
}
You get a type of Animal and actual object of either Dog or Cat so calling a method of Animal will call the method overridden in actual Object of either Dog or Cat if the called method is overridden in base class. It provides you with the flexibility at run time to decide which method to run depending on the actual object and overridden method in base class if any.
您将获得一种 Animal 类型和 Dog 或 Cat 的实际对象,因此如果调用的方法在基类中被覆盖,则调用 Animal 的方法将调用在 Dog 或 Cat 的实际对象中覆盖的方法。它为您提供了在运行时根据实际对象和基类中的重写方法(如果有)决定运行哪个方法的灵活性。
The complete example is as under :-
完整的例子如下:-
package com.test.factory;
public class Animal{
public void shout(){
System.out.println("Parent animal's shout");
}
}
package com.test.factory;
public class Dog extends Animal{
@Override
public void shout(){
System.out.println("bark..");
}
}
package com.test.factory;
public class Horse extends Animal{
@Override
public void shout(){
System.out.println("neigh");
}
}
package com.test.factory;
public class Lion extends Animal{
@Override
public void shout(){
System.out.println("roar..");
}
}
package com.test.factory;
public class AnimalFactory {
public Animal createAnimal(String str){
if(str.equals("dog")){
return new Dog();
}
else if (str.equals("horse")){
return new Horse();
}
else if(str.equals("lion")){
return new Lion();
}
else{
return new Animal();
}
}
}
package com.test.factory;
package com.test.factory;
public class Polymorphism {
public static void main(String[] args){
AnimalFactory factory = new AnimalFactory();
Animal animal = factory.createAnimal("dog");
animal.shout();
animal = factory.createAnimal("lion");
animal.shout();
animal = factory.createAnimal("horse");
animal.shout();
animal = factory.createAnimal("Animal");
animal.shout();
}
}
Output is :-
bark..
roar..
neigh
Parent animal's shout
The AnimalFactory has a createAnimal method which returns Animal. Since Dog, Lion and Horse are all animals. So we are able to create Dog, Lion and Horse objects by using Animal return type. What we achieved using Animal return type is
AnimalFactory 有一个返回 Animal 的 createAnimal 方法。因为狗、狮子和马都是动物。所以我们可以通过使用 Animal 返回类型来创建 Dog、Lion 和 Horse 对象。我们使用 Animal 返回类型实现的是
Animal animal = new Dog();
Animal animal = new Lion();
Animal animal = new Horse();
which is not possible without the Animal return type.
如果没有 Animal 返回类型,这是不可能的。
If I use return type as Dog in createAnimal method then it cannot return Lion or Horse and like wise.
如果我在 createAnimal 方法中使用返回类型为 Dog 则它不能返回 Lion 或 Horse 等。