Java多态/铸造/方法

时间:2015-04-03 15:38:32

标签: java casting polymorphism

对此主题的澄清。因此,举例来说,我有:

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

    Console fav = new Xbox();

  3. 如果所有类都有定义的play()方法。如果我打电话给fav.play();,它会查看Xbox的播放方法,如果它没有播放方法,它会继续在层次结构中找到该方法吗?

  4. 此外,如果我做了((XboxOne)fav).play()它会执行XboxOne的播放方法吗?我也只能在对象层次较低的情况下投射对象吗?

  5. 如果Xbox类有getGamerscore方法,但控制台没有,我会不会 能够运行fav.getGamerScore()

  6. 一般问题:

    =左边的类型显示了调用方法时java会查看哪个类(最具体)? (如果在那里找不到它,它将继续向上层次结构,直到找到方法?)

    右侧的类型代表编译类型。编译java时会查看方法或数据是否属于编译类型,如果是这样,一切都很好?

    时,Java不会再看它的编译类型了。

    Casting只是帮助解决编译问题?就像我想要使用某种方法但我的对象编译类型就像一个接口或抽象类或其他东西,所以我这样投,所以当我尝试访问运行时类型的方法时,编译器不会抱怨?

    如果我说错了,请纠正我,我只想在脑海中清楚地了解所有规则。此外,如果任何人有任何有用的资源,那将是伟大的。

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

5 个答案:

答案 0 :(得分:1)

你需要区分两件事

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

    1. 动态类型
    2. 这是变量在运行时期间的内容,因此在启动程序Console fav = new Xbox()后,fav的动态类型将为Xbox(但静态类型仍为{{1} }})。

      现在提出问题

        

      如果所有类都有定义的播放方法。如果我打电话给fav.play();它将查看Xbox的播放方法,如果它没有播放方法,它将继续向上层次结构,直到找到该方法?

      如果所有类都是基类Console类(至少是抽象方法),那么是。

        

      此外,如果我((XboxOne)收藏).play()它会执行XboxOne的播放方法吗?如果它在层次结构中较低的话,我只能投射一个对象吗?

      你可以随时转发 - 从更具体的(Console)转到更通用的(Xbox);只有在某种程度上才能实现倾斜 - 如果有可能它会成功。因此,通常向下转换为动态类型应该会成功。 (例如Console + Console fav = new Xbox()

        

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

      不,如前所述; (Xbox)console)fav,因此不知道Console的含义。但是,你仍然可以getGamerScore

        

      Casting只是帮助解决编译问题?

      投射可能非常危险,因为您正在对变量做出假设。 如果您致电((XBox) fav).getGamerScore,那么您已经知道该类型必须为((XBox) fav).getGamerScoreXbox可能有误,因为您无法在其中分配任何类型的控制台。

答案 1 :(得分:0)

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

  2. 您将无法将Xbox强制转换为派生类XboxOne。您只能转换为控制台或向下转换为您创建的实际对象的类型(XBox)。如果你没有首先创建一个XBox,你会得到一个运行时ClassCastException。

  3. 如果XBox是getGamerscore,但控制台没有。如果你按照自己的方式构建,则无法调用该方法。如果getGamerscore是Console的抽象方法,你可以调用它。

  4. 对于一些一般性问题。我鼓励你在网上闲聊。但简单地说,当你做这样的事情时:

    Console fav =  new Xbox();
    

    您构造了一个Xbox类型的对象,并分配给一个类型为Console的变量。出于编译时检查的目的,XBox现在是一个控制台,可以传递给需要控制台的方法。看看这篇文章:

    explicit casting from super class to subclass

答案 2 :(得分:0)

  1. 是的,如果你在Xbox中覆盖了play(),那么它将被调用,否则它将使用抽象类中的默认实现。

  2. 您无法将控制台转换为XboxOne。但是,如果您已声明fav属于Xbox类型,那么您可以将其强制转换为XboxOne

  3. 没有

答案 3 :(得分:0)

  

我永远不能直接实例化Console,因为它是抽象的

正确

  

然而,我可以将控制台实例化为xbox

Console fav = new Xbox();

正确

  

如果所有类都有定义的play()方法。如果我调用fav.play();,它会查看Xbox的播放方法,如果它没有播放方法,它会继续在层次结构中找到该方法吗?

正确。这不是现实中的真实情况(它已经过优化),但从概念上讲,你做对了。

  

此外,如果我((XboxOne)fav).play(),它会执行XboxOne的播放方法吗?

不正确的。 fav的对象引用的具体运行时类型是XBox。而XBox不是XBoxOne。所以这样的强制转换会因ClassCastException而失败。您可以将fav投射到XBox,因为“收件人”确实是XBox

  

如果对象在层次结构中较低的话,我也只能投出一个对象吗?

不确定你的意思。强制转换意味着:"我知道你,编译器,只知道fav是一个控制台。但我比你知道的更好,而且我确定它实际上是XBox的一个实例,所以请考虑这个变量引用一个XBox,这样我就可以调用XBox中存在但不存在于Console中的方法。如果运行时证明我错了,我接受了ClassCastException"。

  

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

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

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

一般问题:

     

=左边的类型显示了调用方法时java会查看哪个类(最具体)? (如果在那里找不到它,它将继续向上层次结构,直到找到方法?)

如果"离开"那将是正确的。被"右"取代。

  

右侧的类型代表编译类型。编译java时会查看方法或数据是否属于编译类型,如果是这样,一切都很好?

时,Java不会再看它的编译类型了。

这是正确的是"对"被"左"取代。

  

Casting只是帮助解决编译问题?就像我想要使用某种方法但我的对象编译类型就像一个接口或抽象类或其他东西,所以我这样投,所以当我尝试访问运行时类型的方法时,编译器不会抱怨?

正确。但是,如果对象实际上不是您所投射类型的实例,那么您将在运行时获得ClassCastException。

答案 4 :(得分:0)

  

我永远不能直接实例化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

  

Console fav = new Xbox();

     

如果所有类都有定义的play()方法。如果我打电话给fav.play();它将查看Xbox的播放方法,如果它没有播放方法,它将继续向上层次结构,直到找到该方法?

是的,从某种意义上说。

  

此外,如果我((XboxOne)收藏).play()它会执行XboxOne的播放方法吗?如果它在层次结构中较低的话,我只能投射一个对象吗?

您无法相对于实际实例类型进行向下转换。你可以写(但闻起来不太好)。

    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被声明为控制台,则为否。您可以在getGameScore()中声明Console

  

一般问题:

     

=左边的类型显示了调用方法时java会查看哪个类(最具体)? (如果在那里找不到它,它将继续向上层次结构,直到找到方法?)

不是真的。您必须从上到下考虑继承:当一个类extends为另一个时,继承所有public(和{{1方法/字段。例如,如果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类型。另请注意,从[{1}}继承 Console方法的XBoxOne的实例化类型。

  

右侧的类型代表编译类型。编译java时会查看方法或数据是否属于编译类型,如果是这样,一切都很好?

时,Java不会再看它的编译类型了。

不,见上文。

  

Casting只是帮助解决编译问题?

是的,大部分时间都可以避免。

  

就像我想要使用某种方法,但我的对象编译类型就像一个接口或抽象类或其他东西,所以我投,所以当我尝试访问运行时类型的方法时,编译器不会抱怨?

我认为你在这里左右混合,见上面的评论