簡體   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