【问题标题】:Java Polymorphism/Casting/MethodsJava多态/铸造/方法
【发布时间】:2015-04-04 00:38:56
【问题描述】:

对此主题的澄清。因此,出于示例目的说我有:

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

    控制台收藏 = new Xbox();

  3. 如果所有类都定义了play() 方法。如果我调用fav.play();,它将查看 Xbox 的播放方法,如果它没有播放方法,它会继续向上层级直到找到该方法?

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

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

一般问题:

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

右边的类型只代表编译类型。编译java时会查看方法或数据是否属于编译类型,如果是,一切都好吗? Java 在运行时将不再查看它的编译类型。

强制转换只是帮助解决编译问题?就像我想使用某个方法,但我的对象编译类型就像一个接口或抽象类之类的东西,所以我强制转换,这样编译器就不会在我尝试访问运行时类型的方法时报错?

如果我说错了什么,请纠正我,我只是想把所有规则都弄清楚。另外,如果有人有任何有用的资源,那就太好了。

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

【问题讨论】:

    标签: java casting polymorphism


    【解决方案1】:

    你需要区分两件事

    1. 静态类型

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

    1. 动态类型

    这是运行时变量的样子,所以在你启动程序Console fav = new Xbox()之后,fav的动态类型将是Xbox(但静态类型仍然是Console)。

    现在回答你的问题

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

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

    如果我做了 ((XboxOne)fav).play() ,它会做 XboxOne 的播放方法吗?我也只能投射层次结构中较低的对象吗?

    您总是可以向上转换 - 从更具体的 (Xbox) 到更通用的 (Console);只有在一定程度上,向下转型是可能的——如果有机会它会成功。所以通常向下转换为动态类型应该会成功。 (例如Console fav = new Xbox() + (Xbox)console)

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

    不,如前所述; favConsole,因此不知道您所说的 getGamerScore 是什么意思。但是,您仍然可以使用((XBox) fav).getGamerScore

    强制转换只是帮助解决编译问题?

    强制转换可能非常危险,因为您正在对变量进行假设。 如果你调用((XBox) fav).getGamerScore,那么你已经知道类型必须是Xbox,而Console fav可能是错误的,因为你不能在那里分配任何类型的控制台。

    【讨论】:

      【解决方案2】:
      1. 是的,如果你在 Xbox 中重写了 play(),那么它将被调用,否则它将使用抽象类中的默认实现。

      2. 您无法将控制台投射到 XboxOne。但是,如果您已将 fav 声明为 Xbox 类型,那么您将能够将其转换为 XboxOne

      【讨论】:

        【解决方案3】:

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

        正确

        不过,我可以将控制台实例化为 xbox

        Console fav = new Xbox();
        

        正确

        如果所有类都定义了play() 方法。如果我调用fav.play();,它将查看 Xbox 的播放方法,如果它没有播放方法,它会继续向上层级直到找到该方法?

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

        如果我做了((XboxOne)fav).play(),它会做XboxOne的播放方法吗?

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

        如果对象在层次结构中较低,我也只能转换它是真的吗?

        不确定你的意思。演员表的意思是:“我知道你,编译器,只知道 fav 是一个控制台。但我比你更清楚,而且我确定它实际上是 XBox 的一个实例,所以请考虑这个变量引用一个 XBox ,这样我就可以调用 XBox 中存在的方法,但不能调用控制台中的方法。如果运行时证明我错了,我接受获得 ClassCastException"。

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

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

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

        一般问题:

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

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

        右边的类型只代表编译类型。编译java时会查看方法或数据是否属于编译类型,如果是,一切都好吗? Java 在运行时将不再查看它的编译类型。

        正确的是“右”被“左”取代。

        强制转换只是帮助解决编译问题?就像我想使用某个方法,但我的对象编译类型就像一个接口或抽象类之类的东西,所以我强制转换,这样编译器就不会在我尝试访问运行时类型的方法时报错?

        正确。但是,如果对象实际上不是您转换为的类型的实例,您将在运行时收到 ClassCastException。

        【讨论】:

          【解决方案4】:
          1. 是的,如果你在 XBox 上调用 play 方法并且它不存在,它将调用基类中的方法。

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

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

          关于您的一些一般性问题。我鼓励你在互联网上闲逛。但简单地说,当你做这样的事情时:

          Console fav =  new Xbox();
          

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

          explicit casting from super class to subclass

          【讨论】:

          • 你只能投?怎么是真的?我已经测试了我有一个抽象编译类型 test1= 一个子类运行时类型的代码,并且我转换了 ((runtimeType)test1.runTimeMethod) 并且它可以工作。这不是倒下吗?
          • 查看我的编辑,您只能转换为您实际创建的项目类型。对不起:)。
          【解决方案5】:

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

          你是对的,但是...假设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

          控制台收藏 = new Xbox();

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

          从某种意义上说是的。

          如果我做了 ((XboxOne)fav).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 被声明为控制台,则否。不过你可以在Console 中声明getGameScore()

          一般问题:

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

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

              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 在运行时将不再查看它的编译类型。

          不,见上文。

          强制转换只是帮助解决编译问题?

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

          如果我想使用某个方法,但我的对象编译类型就像一个接口或抽象类或其他东西,所以我进行了转换,以便在我尝试访问运行时类型的方法时编译器不会抱怨?

          我觉得你这里左右混了,看上面的cmets

          【讨论】:

            猜你喜欢
            • 2014-05-29
            • 1970-01-01
            • 1970-01-01
            • 2011-09-17
            • 2011-07-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多