[英]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() {}
}
Console
,因为它很abstract
但是我可以将控制台实例化为xbox
控制台收藏=新Xbox();
如果所有类都有定义的play()
方法。 如果我调用fav.play();
它会查看Xbox的play方法,如果它没有play方法,它将继续沿层次结构扩展,直到找到该方法为止?
同样如果我做了((XboxOne)fav).play()
它会做XboxOne的play方法吗?难道我只能在等级较低的情况下才能投射对象吗?
如果Xbox
类具有getGamerscore
方法,但控制台没有,我可以运行fav.getGamerScore()
吗?
一般的问题:
=左侧的类型显示了在调用方法时java将查找哪个类(最特定)? (如果无法找到该方法,它将继续进行层次结构直到找到该方法?)
右侧的类型仅代表编译类型。 进行编译时,java会查看并查看该方法或数据是否属于编译类型,如果一切正常,则一切正常吗? Java在运行时将不再查看其编译类型。
强制转换是否有助于解决编译问题? 就像我想使用某种方法,但我的对象的编译类型就像接口或抽象类之类的东西一样,因此我强制转换,以便尝试访问运行时类型的方法时编译器不会抱怨吗?
如果我说错了什么,请纠正我,我只是想让所有规则清晰明了。 另外,如果有人有任何有用的资源,那将是很好的。
**我意识到我没有使用游戏界面
您需要区分两件事
这是在编译时已知的,并将用于方法签名查找。 因此,如果您有Console fav = new Xbox()
,则fav
的静态类型将为Console
。 因此,如果您尝试调用fav.play()
,则编译器将在Console
类中查找play
签名; 如果Console
不支持此方法,则Java甚至不会对其进行编译。
这就是变量在运行时的含义,因此,在启动程序Console fav = new Xbox()
, fav
的动态类型将为Xbox
(但静态类型仍为Console
)。
现在您的问题
如果所有类都有定义的play方法。 如果我调用fav.play(); 它会查看Xbox的play方法,如果它没有play方法,它将继续沿层次结构扩展,直到找到该方法为止?
如果就所有类而言,您还指代Console
的基类(至少是抽象方法),则为是。
同样如果我做了((XboxOne)fav).play()它会做XboxOne的play方法吗?难道我只能在等级较低的情况下才能投射对象吗?
您始终可以进行转换-从更特定的Xbox
( Xbox
)转换为更通用的( Console
); 向下转换只能在某种程度上实现-如果有机会成功的话。 因此通常向下转换为动态类型应该可以成功。 (例如, Console fav = new Xbox()
+ (Xbox)console)
。
如果Xbox类具有getGamerscore方法,但控制台没有,我可以运行fav.getGamerScore()吗?
不,如前所述; fav
是Console
,因此不了解getGamerScore
。 但是您仍然可以执行((XBox) fav).getGamerScore
。
强制转换是否有助于解决编译问题?
强制转换可能非常危险,因为您要对变量进行假设。 如果您正在调用((XBox) fav).getGamerScore
,则您已经知道该类型必须为Xbox
并且拥有Console fav
可能是错误的,因为您无法在其中分配任何类型的Console。
是的,如果您在XBox上调用play方法,但该方法不存在,它将在基类中调用该方法。
您将无法将Xbox转换为派生类XboxOne。 您只能转换为Console或转换为您创建的实际对象的类型(XBox)。 如果您首先没有创建XBox,则将获得运行时ClassCastException。
如果XBox是getGamerscore,但控制台没有。 如果像以前那样构造,则将无法调用该方法。 如果getGamerscore是Console的抽象方法,则可以调用它。
对于您的一些一般性问题。 我鼓励您在互联网上闲逛。 简单来说,当您执行以下操作时:
Console fav = new Xbox();
您将构造Xbox类型的对象,并将其分配给Console类型的变量。 出于编译时检查的目的,XBox现在是一个Console,可以传递给需要Console的方法。 在这里查看此帖子:
是的,如果您在Xbox中重写了play(),则它将被调用,否则它将使用抽象类中的默认实现。
您不能将控制台投射到XboxOne。 但是,如果您已将fav声明为Xbox类型,则可以将其投射为XboxOne。
没有
我永远无法直接实例化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
的实例化类型继承了XBox
的play()
方法。
右侧的类型仅代表编译类型。 进行编译时,java会查看并查看该方法或数据是否属于编译类型,如果一切正常,则一切正常吗? Java在运行时将不再查看其编译类型。
不,请参见上面。
强制转换是否有助于解决编译问题?
是的,大多数时候可以避免。
就像我想使用某种方法,但我的对象的编译类型就像接口或抽象类之类的东西一样,因此我强制转换,以便尝试访问运行时类型的方法时编译器不会抱怨吗?
我认为您在这里左右混合,请参阅上面的评论
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.