[英]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.