向下轉型也是編譯看左運行看右嗎
㈠ java向下轉型,有啥作用。求解
向下轉型
將超類的引用強制轉換為子類類型就叫做向下轉型。
注意:將超類的引用賦給為子類類型的變數(沒有進行顯示地強制轉換)是一個編譯
錯誤。
例子:
還是上面的for循環代碼
for(int i=0;i<x.length;i++)
{
if(x[i] instanceof MoreUseful2) // 判斷instanceof左邊的對象是否是右邊的類的實例。
{
MoreUseful2 moreuseful2 = (MoreUseful2)x[i]; // 向下轉型
moreuseful2.u();
}
x[i].g();
}
分析:x[i]可以代表具體的Useful對象類型,當它是MoreUseful2或ExtendsMoreUseful2
對象類型時,就可以調用該對象的額外方法u(),v(),w(),也就是當對象x[i]和Moreusful對
象存在is-a關系時,才可以進行向下轉型,如果要轉換的對象類型與指定的對象類型不
存在is-a關系時,會產生一個ClassCastException異常。
總之:
向下轉型時,對象只能強制轉換為其本身類型或者其超類類型。比如,
當x[i]ExtendsMoreUseful2對象時,可以把他轉換為其本身ExtendsMoreUseful2對象類
型,也可以把它轉換為其基類MoreUseful2類型。但是在編譯時候還不知道這個x[i]是代
表那個具體對象類型只知道這個x[i]是基類類型引用,所以要用這樣的形式" (想要要得
到的類型)x[i] " 進行轉換。x[i]在這里是就我這個例子來說明的,你也可以使用其它的
英文代替,其意義是一切符合規定的需要被轉換的對象。
下面還有個關於向上轉型和向下轉型的例子,
abstract class ClassAbstract1{}
class ClassDerived1 extends ClassAbstract1
{
public void play1()
{
System.out.println("play1() is in the ClassDerived1");
}
}
abstract class ClassAbstract2{public abstract void play2();}
class ClassDerived2 extends ClassAbstract2
{
public void play2()
{
System.out.println("play2() is in the ClassDerived2");
}
}
public class E14_UnCast {
public static void playDemo1(ClassAbstract1 ObjectParameter)
{
((ClassDerived1)ObjectParameter).play1();//向下轉型,可以調用導出類中的擴展方法
}
public static void playDemo2(ClassAbstract2 ObjectParameter)
{
ObjectParameter.play2();//向上轉型,可以調用導出類中的覆蓋方法
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassAbstract1 classabstract = new ClassDerived1();
playDemo1(classabstract);
ClassAbstract2 classabstract2 = new ClassDerived2();
playDemo2(classabstract2);
}
}
運行結果:
play1() is in the ClassDerived1
play2() is in the ClassDerived2
㈡ Java中的強制類型轉換是如何轉換的
java中數據類型的強制轉換是通過強制轉換語句完成的,強制轉換語句的格式為「目標數據類型 變數 = (目標數據類型) 數據;」。下面給出例子:
1、定義兩個位元組數據類型a、b、c,分別賦予1和2和a+b的值,進行加法運算的式子a+b=3,得出的結果「3」將會被編譯環境判定為整形數據,把這個整形數據賦值給c,系統將會報錯,這樣就需要用到格式為「目標數據類型 變數 = (目標數據類型) 數據;」的強制轉換語句。
2、根據強制轉換語句的格式,易得「byte c = (byte)(a+b);」;
3、這樣就把整形數據的「3」賦值給位元組數據類型的c了,其中完成數據的強制類型轉換。
(2)向下轉型也是編譯看左運行看右嗎擴展閱讀:
基本類型 轉換原則:
1、類型轉換主要在在賦值、方法調用、算術運算三種情況下發生。
a、賦值和方法調用 轉換規則:從低位類型到高位類型自動轉換;從高位類型到低位類型需要強制類型轉換:
(1)布爾型和其它基本數據類型之間不能相互轉換;
(2)byte型可以轉換為short、int、、long、float和double;
(3)short可轉換為int、long、float和double;
(4)char可轉換為int、long、float和double;
(5)int可轉換為long、float和double;
(6)long可轉換為float和double;
(7)float可轉換為double;
b、算術運算 中的類型轉換:
1、基本就是先轉換為高位數據類型,再參加運算,結果也是最高位的數據類型;
2、byte short char運算會轉換為Int;
(1)如操作數之一為double,則另一個操作數先被轉化為double,再參與算術運算。
(2)如兩操作數均不為double,當操作數之一為float,則另一操作數先被轉換為float,再參與運算。
(3)如兩操作數均不為double或float,當操作數之一為long,、則另一操作數先被轉換為long,再參與算術運算。
(4)如兩操作數均不為double、float或long,則兩操作數先被轉換為int,再參與運算。
特殊:
(1)如採用+=、*=等縮略形式的運算符,系統會自動強制將運算結果轉換為目標變數的類型。
(2) 當運算符為自動遞增運算符(++)或自動遞減運算符(--)時,如果操作數為byte,short或char類型不發生改變;
㈢ Collection coll = new ArrayList();是什麼意思求詳解
親,就像樓上的說的,我們動物定義的是介面,但是呢,我們new的是狗,不是new 的動物,所以說你的說法是有問題的,是new 了一個狗,然後呢有一個地址是指向狗的,方便你去使用這個狗。我們不僅能夠new一個狗還可以new一個豬,new 一個牛。但是他們都是動物,也就是都是介面。
介面是不能new的這個是正確的說法。包括抽象類也是不能new的。
希望可以幫助到你,有什麼問題你都可以追問,沒問題,望採納,謝謝
㈣ 誰告訴我java多態里類變數是怎麼賦值的
我的理解是看對象前面的類型。
第一個的類型是A,所以輸出的屬性就是A裡面的屬性,然後方法的話,應為子類重寫了父類的方法,所以使用子類的。
第二個。對象的類型是B,是由a強制轉換來的,還是針對屬性看a的,方法是看b的
最終的總結是:
成員變數:編譯看左邊,運行看左邊;
成員方法:編譯看左邊,運行看右邊:
靜態方法: 編譯看左邊,運行看左邊
㈤ Java中數組向下轉型,編譯沒問題,運行卻報錯
異常提示不可以直接轉,換這樣寫String[] as = Arrays.asList(a).toArray(new String[0]);
樓主你首先異常那裡概念沒有弄清,在java中分為運行時異常runtime Exception,以及一般的Exception,如圖
你這個就屬於運行時異常,編譯是不會報錯的,編譯不報錯不代表沒有錯誤,你寫個int a =1;int b = 0; 輸出 a/b編譯也不會出粗,但是運行就報除數不為0異常了。
㈥ 在Java中什麼是父類引用指向子類對象
這個是我很早之前學習到「多態」時候整理的筆記。
送你了!希望對你有用!
Java的多態性
面向對象編程有三個特徵,即封裝、繼承和多態。
封裝隱藏了類的內部實現機制,從而可以在不影響使用者的前提下改變類的內部結構,同時保護了數據。
繼承是為了重用父類代碼,同時為實現多態性作準備。那麼什麼是多態呢?
方法的重寫、重載與動態連接構成多態性。Java之所以引入多態的概念,原因之一是它在類的繼承問題上和C++不同,後者允許多繼承,這確實給其帶來的非常強大的功能,但是復雜的繼承關系也給C++開發者帶來了更大的麻煩,為了規避風險,Java只允許單繼承,派生類與基類間有IS-A的關系(即「貓」is a 「動物」)。這樣做雖然保證了繼承關系的簡單明了,但是勢必在功能上有很大的限制,所以,Java引入了多態性的概念以彌補這點的不足,此外,抽象類和介面也是解決單繼承規定限制的重要手段。同時,多態也是面向對象編程的精髓所在。
要理解多態性,首先要知道什麼是「向上轉型」。
我定義了一個子類Cat,它繼承了Animal類,那麼後者就是前者是父類。我可以通過
Cat c = new Cat();
實例化一個Cat的對象,這個不難理解。但當我這樣定義時:
Animal a = new Cat();
這代表什麼意思呢?
很簡單,它表示我定義了一個Animal類型的引用,指向新建的Cat類型的對象。由於Cat是繼承自它的父類Animal,所以Animal類型的引用是可以指向Cat類型的對象的。那麼這樣做有什麼意義呢?因為子類是對父類的一個改進和擴充,所以一般子類在功能上較父類更強大,屬性較父類更獨特,
定義一個父類類型的引用指向一個子類的對象既可以使用子類強大的功能,又可以抽取父類的共性。
所以,父類類型的引用可以調用父類中定義的所有屬性和方法,而對於子類中定義而父類中沒有的方法,它是無可奈何的;
同時,父類中的一個方法只有在在父類中定義而在子類中沒有重寫的情況下,才可以被父類類型的引用調用;
對於父類中定義的方法,如果子類中重寫了該方法,那麼父類類型的引用將會調用子類中的這個方法,這就是動態連接。
看下面這段程序:
class Father{
public void func1(){
func2();
}
//這是父類中的func2()方法,因為下面的子類中重寫了該方法
//所以在父類類型的引用中調用時,這個方法將不再有效
//取而代之的是將調用子類中重寫的func2()方法
public void func2(){
System.out.println("AAA");
}
}
class Child extends Father{
//func1(int i)是對func1()方法的一個重載
//由於在父類中沒有定義這個方法,所以它不能被父類類型的引用調用
//所以在下面的main方法中child.func1(68)是不對的
public void func1(int i){
System.out.println("BBB");
}
//func2()重寫了父類Father中的func2()方法
//如果父類類型的引用中調用了func2()方法,那麼必然是子類中重寫的這個方法
public void func2(){
System.out.println("CCC");
}
}
public class PolymorphismTest {
public static void main(String[] args) {
Father child = new Child();
child.func1();//列印結果將會是什麼?
}
}
上面的程序是個很典型的多態的例子。子類Child繼承了父類Father,並重載了父類的func1()方法,重寫了父類的func2()方法。重載後的func1(int i)和func1()不再是同一個方法,由於父類中沒有func1(int i),那麼,父類類型的引用child就不能調用func1(int i)方法。而子類重寫了func2()方法,那麼父類類型的引用child在調用該方法時將會調用子類中重寫的func2()。
那麼該程序將會列印出什麼樣的結果呢?
很顯然,應該是「CCC」。
對於多態,可以總結它為:
一、使用父類類型的引用指向子類的對象;
二、該引用只能調用父類中定義的方法和變數;
三、如果子類中重寫了父類中的一個方法,那麼在調用這個方法的時候,將會調用子類中的這個方法;(動態連接、動態調用)
四、變數不能被重寫(覆蓋),」重寫「的概念只針對方法,如果在子類中」重寫「了父類中的變數,那麼在編譯時會報錯。
****************************************************************************************************************************
多態詳解(整理)2008-09-03 19:29多態是通過:
1 介面 和 實現介面並覆蓋介面中同一方法的幾不同的類體現的
2 父類 和 繼承父類並覆蓋父類中同一方法的幾個不同子類實現的.
一、基本概念
多態性:發送消息給某個對象,讓該對象自行決定響應何種行為。
通過將子類對象引用賦值給超類對象引用變數來實現動態方法調用。
java 的這種機制遵循一個原則:當超類對象引用變數引用子類對象時,被引用對象的類型而不是引用變數的類型決定了調用誰的成員方法,但是這個被調用的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法。
1. 如果a是類A的一個引用,那麼,a可以指向類A的一個實例,或者說指向類A的一個子類。
2. 如果a是介面A的一個引用,那麼,a必須指向實現了介面A的一個類的實例。
二、Java多態性實現機制
SUN目前的JVM實現機制,類實例的引用就是指向一個句柄(handle)的指針,這個句柄是一對指針:
一個指針指向一張表格,實際上這個表格也有兩個指針(一個指針指向一個包含了對象的方法表,另外一個指向類對象,表明該對象所屬的類型);
另一個指針指向一塊從java堆中為分配出來內存空間。
三、總結
1、通過將子類對象引用賦值給超類對象引用變數來實現動態方法調用。
DerivedC c2=new DerivedC();
BaseClass a1= c2; //BaseClass 基類,DerivedC是繼承自BaseClass的子類
a1.play(); //play()在BaseClass,DerivedC中均有定義,即子類覆寫了該方法
分析:
* 為什麼子類的類型的對象實例可以覆給超類引用?
自動實現向上轉型。通過該語句,編譯器自動將子類實例向上移動,成為通用類型BaseClass;
* a.play()將執行子類還是父類定義的方法?
子類的。在運行時期,將根據a這個對象引用實際的類型來獲取對應的方法。所以才有多態性。一個基類的對象引用,被賦予不同的子類對象引用,執行該方法時,將表現出不同的行為。
在a1=c2的時候,仍然是存在兩個句柄,a1和c2,但是a1和c2擁有同一塊數據內存塊和不同的函數表。
2、不能把父類對象引用賦給子類對象引用變數
BaseClass a2=new BaseClass();
DerivedC c1=a2;//出錯
在java裡面,向上轉型是自動進行的,但是向下轉型卻不是,需要我們自己定義強制進行。
c1=(DerivedC)a2; 進行強制轉化,也就是向下轉型.
3、記住一個很簡單又很復雜的規則,一個類型引用只能引用引用類型自身含有的方法和變數。
你可能說這個規則不對的,因為父類引用指向子類對象的時候,最後執行的是子類的方法的。
其實這並不矛盾,那是因為採用了後期綁定,動態運行的時候又根據型別去調用了子類的方法。而假若子類的這個方法在父類中並沒有定義,則會出錯。
例如,DerivedC類在繼承BaseClass中定義的函數外,還增加了幾個函數(例如 myFun())
分析:
當你使用父類引用指向子類的時候,其實jvm已經使用了編譯器產生的類型信息調整轉換了。
這里你可以這樣理解,相當於把不是父類中含有的函數從虛擬函數表中設置為不可見的。注意有可能虛擬函數表中有些函數地址由於在子類中已經被改寫了,所以對象虛擬函數表中虛擬函數項目地址已經被設置為子類中完成的方法體的地址了。
4、Java與C++多態性的比較
jvm關於多態性支持解決方法是和c++中幾乎一樣的,
只是c++中編譯器很多是把類型信息和虛擬函數信息都放在一個虛擬函數表中,但是利用某種技術來區別。
Java把類型信息和函數信息分開放。Java中在繼承以後,子類會重新設置自己的虛擬函數表,這個虛擬函數表中的項目有由兩部分組成。從父類繼承的虛擬函數和子類自己的虛擬函數。
虛擬函數調用是經過虛擬函數表間接調用的,所以才得以實現多態的。
Java的所有函數,除了被聲明為final的,都是用後期綁定。
四. 1個行為,不同的對象,他們具體體現出來的方式不一樣,
比如: 方法重載 overloading 以及 方法重寫(覆蓋)override
class Human{
void run(){輸出 人在跑}
}
class Man extends Human{
void run(){輸出 男人在跑}
}
這個時候,同是跑,不同的對象,不一樣(這個是方法覆蓋的例子)
class Test{
void out(String str){輸出 str}
void out(int i){輸出 i}
}
這個例子是方法重載,方法名相同,參數表不同
ok,明白了這些還不夠,還用人在跑舉例
Human ahuman=new Man();
這樣我等於實例化了一個Man的對象,並聲明了一個Human的引用,讓它去指向Man這個對象
意思是說,把 Man這個對象當 Human看了.
比如去動物園,你看見了一個動物,不知道它是什麼, "這是什麼動物? " "這是大熊貓! "
這2句話,就是最好的證明,因為不知道它是大熊貓,但知道它的父類是動物,所以,
這個大熊貓對象,你把它當成其父類 動物看,這樣子合情合理.
這種方式下要注意 new Man();的確實例化了Man對象,所以 ahuman.run()這個方法 輸出的 是 "男人在跑 "
如果在子類 Man下你 寫了一些它獨有的方法 比如 eat(),而Human沒有這個方法,
在調用eat方法時,一定要注意 強制類型轉換 ((Man)ahuman).eat(),這樣才可以...
對介面來說,情況是類似的...
實例:
package domatic;
//定義超類superA
class superA {
int i = 100;
void fun(int j) {
j = i;
System.out.println("This is superA");
}
}
// 定義superA的子類subB
class subB extends superA {
int m = 1;
void fun(int aa) {
System.out.println("This is subB");
}
}
// 定義superA的子類subC
class subC extends superA {
int n = 1;
void fun(int cc) {
System.out.println("This is subC");
}
}
class Test {
public static void main(String[] args) {
superA a = new superA();
subB b = new subB();
subC c = new subC();
a = b;
a.fun(100);
a = c;
a.fun(200);
}
}
/*
* 上述代碼中subB和subC是超類superA的子類,我們在類Test中聲明了3個引用變數a, b,
* c,通過將子類對象引用賦值給超類對象引用變數來實現動態方法調用。也許有人會問:
* "為什麼(1)和(2)不輸出:This is superA"。
* java的這種機制遵循一個原則:當超類對象引用變數引用子類對象時,
* 被引用對象的類型而不是引用變數的類型決定了調用誰的成員方法,
* 但是這個被調用的方法必須是在超類中定義過的,
* 也就是說被子類覆蓋的方法。
* 所以,不要被上例中(1)和(2)所迷惑,雖然寫成a.fun(),但是由於(1)中的a被b賦值,
* 指向了子類subB的一個實例,因而(1)所調用的fun()實際上是子類subB的成員方法fun(),
* 它覆蓋了超類superA的成員方法fun();同樣(2)調用的是子類subC的成員方法fun()。
* 另外,如果子類繼承的超類是一個抽象類,雖然抽象類不能通過new操作符實例化,
* 但是可以創建抽象類的對象引用指向子類對象,以實現運行時多態性。具體的實現方法同上例。
* 不過,抽象類的子類必須覆蓋實現超類中的所有的抽象方法,
* 否則子類必須被abstract修飾符修飾,當然也就不能被實例化了
*/
以上大多數是以子類覆蓋父類的方法實現多態.下面是另一種實現多態的方法-----------重寫父類方法
1.JAVA里沒有多繼承,一個類之能有一個父類。而繼承的表現就是多態。一個父類可以有多個子類,而在子類里可以重寫父類的方法(例如方法print()),這樣每個子類里重寫的代碼不一樣,自然表現形式就不一樣。這樣用父類的變數去引用不同的子類,在調用這個相同的方法print()的時候得到的結果和表現形式就不一樣了,這就是多態,相同的消息(也就是調用相同的方法)會有不同的結果。舉例說明:
//父類
public class Father{
//父類有一個打孩子方法
public void hitChild(){
}
}
//子類1
public class Son1 extends Father{
//重寫父類打孩子方法
public void hitChild(){
System.out.println("為什麼打我?我做錯什麼了!");
}
}
//子類2
public class Son2 extends Father{
//重寫父類打孩子方法
public void hitChild(){
System.out.println("我知道錯了,別打了!");
}
}
//子類3
public class Son3 extends Father{
//重寫父類打孩子方法
public void hitChild(){
System.out.println("我跑,你打不著!");
}
}
//測試類
public class Test{
public static void main(String args[]){
Father father;
father = new Son1();
father.hitChild();
father = new Son2();
father.hitChild();
father = new Son3();
father.hitChild();
}
}
都調用了相同的方法,出現了不同的結果!這就是多態的表現!
****************************************************************************************************************************
㈦ 在java多態中,編譯看左邊,運行看右邊是什麼意思,哪位大俠能幫忙詳細解釋一下 謝謝了.
Animal c = new Cat(); 左邊是 Animal 類(或介面) 右邊是 Cat()類; 在編譯的時候編譯器不管你右邊是什麼類,只要左邊的Animal類(或介面)能編譯通過就不會報錯。但是運行的時候就要按照右邊的Cat()類實際情況來運行。
㈧ java 請高手們舉個向下轉型的例子,有點不懂下轉型。
向上轉型
我們在現實中常常這樣說:這個人會唱歌。在這里,我們並不關心這個人是黑人還是白人,是成人還是小孩,也就是說我們更傾向於使用抽象概念「人」。再例如,麻雀是鳥類的一種(鳥類的子類),而鳥類則是動物中的一種(動物的子類)。我們現實中也經常這樣說:麻雀是鳥。這兩種說法實際上就是所謂的向上轉型,通俗地說就是子類轉型成父類。這也符合Java提倡的面向抽象編程思想。來看下面的代碼:
package a.b;
public class A {
public void a1() {
System.out.println("Superclass");
}
}
A的子類B:
package a.b;
public class B extends A {
public void a1() {
System.out.println("Childrenclass"); //覆蓋父類方法
}
public void b1(){} //B類定義了自己的新方法
}
C類:
package a.b;
public class C {
public static void main(String[] args) {
A a = new B(); //向上轉型
a.a1();
}
}
如果運行C,輸出的是Superclass 還是Childrenclass?不是你原來預期的Superclass,而是Childrenclass。這是因為a實際上指向的是一個子類對象。當然,你不用擔心,Java虛擬機會自動准確地識別出究竟該調用哪個具體的方法。不過,由於向上轉型,a對象會遺失和父類不同的方法,例如b1()。有人可能會提出疑問:這不是多此一舉嗎?我們完全可以這樣寫:
B a = new B();
a.a1();
確實如此!但這樣就喪失了面向抽象的編程特色,降低了可擴展性。其實,不僅僅如此,向上轉型還可以減輕編程工作量。來看下面的顯示器類Monitor:
package a.b;
public class Monitor{
public void displayText() {}
public void displayGraphics() {}
}
液晶顯示器類LCDMonitor是Monitor的子類:
package a.b;
public class LCDMonitor extends Monitor {
public void displayText() {
System.out.println("LCD display text");
}
public void displayGraphics() {
System.out.println("LCD display graphics");
}
}
陰極射線管顯示器類CRTMonitor自然也是Monitor的子類:
package a.b;
public class CRTMonitor extends Monitor {
public void displayText() {
System.out.println("CRT display text");
}
public void displayGraphics() {
System.out.println("CRT display graphics");
}
}
等離子顯示器PlasmaMonitor也是Monitor的子類:
package a.b;
public class PlasmaMonitor extends Monitor {
public void displayText() {
System.out.println("Plasma display text");
}
public void displayGraphics() {
System.out.println("Plasma display graphics");
}
}
現在有一個MyMonitor類。假設沒有向上轉型,MyMonitor類代碼如下:
package a.b;
public class MyMonitor {
public static void main(String[] args) {
run(new LCDMonitor());
run(new CRTMonitor());
run(new PlasmaMonitor());
}
public static void run(LCDMonitor monitor) {
monitor.displayText();
monitor.displayGraphics();
}
public static void run(CRTMonitor monitor) {
monitor.displayText();
monitor.displayGraphics();
}
public static void run(PlasmaMonitor monitor) {
monitor.displayText();
monitor.displayGraphics();
}
}
可能你已經意識到上述代碼有很多重復代碼,而且也不易維護。有了向上轉型,代碼可以更為簡潔:
package a.b;
public class MyMonitor {
public static void main(String[] args) {
run(new LCDMonitor()); //向上轉型
run(new CRTMonitor()); //向上轉型
run(new PlasmaMonitor()); //向上轉型
}
public static void run(Monitor monitor) { //父類實例作為參數
monitor.displayText();
monitor.displayGraphics();
}
}
我們也可以採用介面的方式,例如:
package a.b;
public interface Monitor {
abstract void displayText();
abstract void displayGraphics();
}
將液晶顯示器類LCDMonitor稍作修改:
package a.b;
public class LCDMonitor implements Monitor {
public void displayText() {
System.out.println("LCD display text");
}
public void displayGraphics() {
System.out.println("LCD display graphics");
}
}
CRTMonitor、PlasmaMonitor類的修改方法與LCDMonitor類似,而MyMonitor可以不不作任何修改。
可以看出,向上轉型體現了類的多態性,增強了程序的簡潔性。
5.13.2 向下轉型
子類轉型成父類是向上轉型,反過來說,父類轉型成子類就是向下轉型。但是,向下轉型可能會帶來一些問題:我們可以說麻雀是鳥,但不能說鳥就是麻雀。來看下面的例子:
A類:
package a.b;
public class A {
void aMthod() {
System.out.println("A method");
}
}
A的子類B:
package a.b;
public class B extends A {
void bMethod1() {
System.out.println("B method 1");
}
void bMethod2() {
System.out.println("B method 2");
}
}
C類:
package a.b;
public class C {
public static void main(String[] args) {
A a1 = new B(); // 向上轉型
a1.aMthod(); // 調用父類aMthod(),a1遺失B類方法bMethod1()、bMethod2()
B b1 = (B) a1; // 向下轉型,編譯無錯誤,運行時無錯誤
b1.aMthod(); // 調用父類A方法
b1.bMethod1(); // 調用B類方法
b1.bMethod2(); // 調用B類方法
A a2 = new A();
B b2 = (B) a2; // 向下轉型,編譯無錯誤,運行時將出錯
b2.aMthod();
b2.bMethod1();
b2.bMethod2();
}
}
從上面的代碼我們可以得出這樣一個結論:向下轉型需要使用強制轉換。運行C程序,控制台將輸出:
Exception in thread "main" java.lang.ClassCastException: a.b.A cannot be cast to a.b.B at
a.b.C.main(C.java:14)
A method
A method
B method 1
B method 2
其實黑體部分的向下轉型代碼後的注釋已經提示你將發生運行時錯誤。為什麼前一句向下轉型代碼可以,而後一句代碼卻出錯?這是因為a1指向一個子類B的對象,所以子類B的實例對象b1當然也可以指向a1。而a2是一個父類對象,子類對象b2不能指向父類對象a2。那麼如何避免在執行向下轉型時發生運行時ClassCastException異常?使用5.7.7節學過的instanceof就可以了。我們修改一下C類的代碼:
A a2 = new A();
if (a2 instanceof B) {
B b2 = (B) a2;
b2.aMthod();
b2.bMethod1();
b2.bMethod2();
}
這樣處理後,就不用擔心類型轉換時發生ClassCastException異常了。
㈨ java中向上轉型,向下轉型,強制類型轉換的原理
第一個OK,可以正確編譯,可以正確運行,因為X是A,A是B的父類,所以當然你構造一個B,相當於也就是構造了一個A所以,X可以賦值到一個B的實例。最簡單理解,就是任何一個對象都是Object的子類,你可以定義一個Object來看。
第二個就不行,不能編譯,也不能運行。都是要求你要做強制轉換
第三個可以編譯,也可以運行,只是有可能在你使用y的時候報錯
第四個也可以編譯,也可以運行,因為這個B就是A的子類,所以當然可以當作一個A來用。
第2個,聲明對象只是說x,是A這個類型的。但是構建的時候,才是創建實例的時候。好比你聲明一個x是A 類,這個時候,你就可以後面給他賦值到所有A類當中的任何一個實例。而new A();只是創建一個A的實例,來賦值,這是眾多賦值方法的一種
第三個,強制轉換的原理,就是一個類,需要他用什麼定義來使用,就轉換成這個定義後,再繼續使用。因為本質上一個類都是存儲在內存里的,按照固定格式,有些時候程序自身是不知道的,只有你自己清楚。最常用的地方,就是把一個類放入Map裡面,再取出來的時候,只有你自己知道裡面放的是什麼,所以要強制類型轉換後,才可以接著用。內存分配方面不會有任何變化,你基本不用操心。
㈩ java中,什麼時候需要new來實例化
(1)同一個對象在不同時刻體現出來的不同狀態。
(2)多態的前提:
A:有繼承或者實現關系。
B:有方法重寫。
C:有父類或者父介面引用指向子類對象。
多態的分類:
a:具體類多態
class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
b:抽象類多態
abstract class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
c:介面多態
interface Fu {}
class Zi implements Fu {}
Fu f = new Zi();
(3)多態中的成員訪問特點
A:成員變數
編譯看左邊,運行看左邊
B:構造方法
子類的構造都會默認訪問父類構造
C:成員方法
編譯看左邊,運行看右邊
D:靜態方法
編譯看左邊,運行看左邊
為什麼?
因為成員方法有重寫。
(4)多態的好處:
A:提高代碼的維護性(繼承體現)
B:提高代碼的擴展性(多態體現)
(5)多態的弊端:
父不能使用子的特有功能。
現象:
子可以當作父使用,父不能當作子使用。
(6)多態中的轉型
A:向上轉型
從子到父
B:向下轉型
從父到子