繁体   English   中英

Java多态性/铸造/方法

[英]Java Polymorphism/Casting/Methods

有关此主题的说明。 因此,出于示例目的,我有:

public interface Gaming {
   void play;
}

public abstract class Console implements Gaming {
   void play() {}
}

public class Xbox extends Console {
   void play() {}
}

public class XboxOne extends Xbox {
   void play() {}
}
  1. 我永远无法直接实例化Console ,因为它很abstract
  2. 但是我可以将控制台实例化为xbox

    控制台收藏=新Xbox();

  3. 如果所有类都有定义的play()方法。 如果我调用fav.play(); 它会查看Xbox的play方法,如果它没有play方法,它将继续沿层次结构扩展,直到找到该方法为止?

  4. 同样如果我做了((XboxOne)fav).play()它会做XboxOne的play方法吗?难道我只能在等级较低的情况下才能投射对象吗?

  5. 如果Xbox类具有getGamerscore方法,但控制台没有,我可以运行fav.getGamerScore()吗?

一般的问题:

=左侧的类型显示了在调用方法时java将查找哪个类(最特定)? (如果无法找到该方法,它将继续进行层次结构直到找到该方法?)

右侧的类型仅代表编译类型。 进行编译时,java会查看并查看该方法或数据是否属于编译类型,如果一切正常,则一切正常吗? Java在运行时将不再查看其编译类型。

强制转换是否有助于解决编译问题? 就像我想使用某种方法,但我的对象的编译类型就像接口或抽象类之类的东西一样,因此我强制转换,以便尝试访问运行时类型的方法时编译器不会抱怨吗?

如果我说错了什么,请纠正我,我只是想让所有规则清晰明了。 另外,如果有人有任何有用的资源,那将是很好的。

**我意识到我没有使用游戏界面

您需要区分两件事

  1. 静态型

这是在编译时已知的,并将用于方法签名查找。 因此,如果您有Console fav = new Xbox() ,则fav的静态类型将为Console 因此,如果您尝试调用fav.play() ,则编译器将在Console类中查找play签名; 如果Console不支持此方法,则Java甚至不会对其进行编译。

  1. 动态型

这就是变量在运行时的含义,因此,在启动程序Console fav = new Xbox()fav的动态类型将为Xbox (但静态类型仍为Console )。

现在您的问题

如果所有类都有定义的play方法。 如果我调用fav.play(); 它会查看Xbox的play方法,如果它没有play方法,它将继续沿层次结构扩展,直到找到该方法为止?

如果就所有类而言,您还指代Console的基类(至少是抽象方法),则为是。

同样如果我做了((XboxOne)fav).play()它会做XboxOne的play方法吗?难道我只能在等级较低的情况下才能投射对象吗?

您始终可以进行转换-从更特定的XboxXbox )转换为更通用的( Console ); 向下转换只能在某种程度上实现-如果有机会成功的话。 因此通常向下转换为动态类型应该可以成功。 (例如, Console fav = new Xbox() + (Xbox)console)

如果Xbox类具有getGamerscore方法,但控制台没有,我可以运行fav.getGamerScore()吗?

不,如前所述; favConsole ,因此不了解getGamerScore 但是您仍然可以执行((XBox) fav).getGamerScore

强制转换是否有助于解决编译问题?

强制转换可能非常危险,因为您要对变量进行假设。 如果您正在调用((XBox) fav).getGamerScore ,则您已经知道该类型必须为Xbox并且拥有Console fav可能是错误的,因为您无法在其中分配任何类型的Console。

  1. 是的,如果您在XBox上调用play方法,但该方法不存在,它将在基类中调用该方法。

  2. 您将无法将Xbox转换为派生类XboxOne。 您只能转换为Console或转换为您创建的实际对象的类型(XBox)。 如果您首先没有创建XBox,则将获得运行时ClassCastException。

  3. 如果XBox是getGamerscore,但控制台没有。 如果像以前那样构造,则将无法调用该方法。 如果getGamerscore是Console的抽象方法,则可以调用它。

对于您的一些一般性问题。 我鼓励您在互联网上闲逛。 简单来说,当您执行以下操作时:

Console fav =  new Xbox();

您将构造Xbox类型的对象,并将其分配给Console类型的变量。 出于编译时检查的目的,XBox现在是一个Console,可以传递给需要Console的方法。 在这里查看此帖子:

从父类到子类的显式转换

  1. 是的,如果您在Xbox中重写了play(),则它将被调用,否则它将使用抽象类中的默认实现。

  2. 您不能将控制台投射到XboxOne。 但是,如果您已将fav声明为Xbox类型,则可以将其投射为XboxOne。

  3. 没有

我永远无法直接实例化Console,因为它很抽象

正确

但是我可以将控制台实例化为xbox

 Console fav = new Xbox(); 

正确

如果所有类都有定义的play()方法。 如果我调用fav.play(); 它会查看Xbox的play方法,如果它没有play方法,它将继续沿层次结构扩展,直到找到该方法为止?

正确。 这不是现实中实际发生的情况(经过优化),但是从概念上讲,您做对了。

同样如果我做了((XboxOne)fav).play() ,那么XboxOne的play方法可以吗?

不正确 fav引用的对象的具体运行时类型为XBox XBox不是XBoxOne。 因此,此类转换将因ClassCastException而失败。 您可以将fav投射到XBox ,因为fav确实是XBox

我也只能在层次结构中较低的对象上强制转换吗?

不知道这是什么意思。 强制转换的意思是:“我知道您,编译器,只知道fav是一个控制台。但是我比您更了解,而且我确定它实际上是XBox的实例,因此请考虑该变量引用了XBox。 ,这样我就可以调用XBox中存在的方法,但不能调用Console中的方法。如果运行时证明我错了,我将接受ClassCastException”。

如果Xbox类具有getGamerscore方法,但控制台没有,我可以运行fav.getGamerScore()吗?

不,您不会,因为fav的编译时间是Console,而Console没有此方法。 您必须将变量强制转换为XBox:

XBox xbox = (XBox) fav;
xbox.getGamerScore();

一般的问题:

=左侧的类型显示了在调用方法时java将查找哪个类(最特定)? (如果无法找到该方法,它将继续进行层次结构直到找到该方法?)

如果将“ left”替换为“ right”,那将是正确的。

右侧的类型仅代表编译类型。 进行编译时,java会查看并查看该方法或数据是否属于编译类型,如果一切正常,则一切正常吗? Java在运行时将不再查看其编译类型。

正确的是将“ right”替换为“ left”。

强制转换是否有助于解决编译问题? 就像我想使用某种方法,但我的对象的编译类型就像接口或抽象类之类的东西一样,因此我强制转换,以便尝试访问运行时类型的方法时编译器不会抱怨吗?

正确。 但是,如果对象实际上不是强制转换为该类型的实例,则在运行时您将获得ClassCastException。

我永远无法直接实例化Console,因为它很抽象

您是对的,但是...假设Console定义为

public abstract class Console implements Gaming {
   // no impl. not needed because already declared in Gaming
   // just for clarity
   public abstract void play(); 
}

您可以使用以下方法直接实例化Console

Console myAnonymousConsole = new Console() {
   public void play() { System.out.println("Hello there"); }
};

但是我可以将控制台实例化为xbox

再次正确,因为Xbox不是abstract

控制台收藏=新Xbox();

如果所有类都有定义的play()方法。 如果我调用fav.play(); 它会查看Xbox的play方法,如果它没有play方法,它将继续沿层次结构扩展,直到找到该方法为止?

是的,在某种意义上。

同样如果我做了((XboxOne)fav).play()它会做XboxOne的play方法吗?难道我只能在等级较低的情况下才能投射对象吗?

您不能相对于实际实例类型向下转换。 您可以写(但味道不好)。

    Console a = new XBoxOne();
    XBox b = (XBox)a; // ok because a is-a Xbox
    XBoxOne c = (XBoxOne)a; // ok because a is-a XBoxOne

    Console a = new XBox();
    XBox b = (XBox)a; // ok because a is-a Xbox
    XBoxOne c = (XBoxOne)a; // ko! because a is-not-a XBoxOne

该检查在运行时完成。 在第二个示例中引发ClassCastException

如果Xbox类具有getGamerscore方法,但控制台没有,我可以运行fav.getGamerScore()吗?

如果fav被声明为控制台,则为否。 您可以在Console声明getGameScore()

一般的问题:

=左侧的类型显示了在调用方法时java将查找哪个类(最特定)? (如果无法找到该方法,它将继续进行层次结构直到找到该方法?)

并不是的。 您必须考虑从上到下的继承 :当一个类extends另一个类时,它将继承所有public (和protected )方法/字段。 例如,如果XBoxOne没有定义play()方法,则从XBox继承它。 回到您的问题,就以左类型(此处为Console )声明的方法而言,所调用的右方法实现将由实例的实际运行类型确定-这是多态性

    public class XBox extends Console {
       public void play() { System.out.println("In XBox"); 
    }
    public class PS3 extends Console {
       public void play() { System.out.println("In PS3"); 
    }
    List<Console> consoles = Arrays.asList(new XBoxOne(), new PS3());
    for (Console c : consoles) {
       c.play(); // polymorphism here
    } 

版画

In XBox
In PS3

即使List看到 Console类型。 还要注意, XBoxOne的实例化类型继承XBoxplay()方法。

右侧的类型仅代表编译类型。 进行编译时,java会查看并查看该方法或数据是否属于编译类型,如果一切正常,则一切正常吗? Java在运行时将不再查看其编译类型。

不,请参见上面。

强制转换是否有助于解决编译问题?

是的,大多数时候可以避免。

就像我想使用某种方法,但我的对象的编译类型就像接口或抽象类之类的东西一样,因此我强制转换,以便尝试访问运行时类型的方法时编译器不会抱怨吗?

我认为您在这里左右混合,请参阅上面的评论

暂无
暂无

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

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