Java多態(tài)的使用注意事項
Java多態(tài)是如何實現(xiàn)的?
Java的多態(tài)和C++一樣,是通過延時綁定(late binding)或者說運行時綁定(runtime binding)來實現(xiàn)的。當調用某一個對象引用的方法時,因為編譯器并不知道這個引用到底指向的是變量聲明時說明的類型對象,還是該類型子類的對象。因此編譯器無法為這次調用綁定到具體的某個方法。只有通過java中的運行時類型識別(RTTI, Runtime type identification)在運行時綁定到具體的方法。下面是一個具體的例子:
class shape
{
public void draw()
{
print("shape");
}
}
class triangle extends shape
{
public void draw()
{
print("triangle");
}
}
public class Polymorphism {
public static void main(String[] args)
{
shape s=new triangle();
s.draw();
}
結果是triangle
s是一個shape引用,但是在運行時因為是triangle對象,所以還是調用了triangle的draw方法。
Java多態(tài)中的一些陷阱
重寫私有方法?
Java里面是不能重寫私有方法的,這個其實很好理解,因為私有方法在子類是不可見的。子類沒有繼承父類的私有方法,更談不上重寫了。因此在子類中的同名方法是一個全新的方法。
public class Polymorphism {
private void show()
{
print("show parent");
}
public static void main(String[] args)
{
Polymorphism p=new privateMethod();
p.show();
}
}
class privateMethod extends Polymorphism
{
public void show()
{
print("show derived");
}
}
結果是 show parent
字段和靜態(tài)方法的多態(tài)?
子類可以繼承父類的非私有字段,子類的字段是否也具有多態(tài)性呢?我們來看一個實際的例子:
class shape
{
protected int perimeter=1;
public void draw()
{
print("shape");
}
public int getPerimeter()
{
return perimeter;
}
}
class triangle extends shape
{
int perimeter=3;
public void draw()
{
print("triangle");
}
public int getPerimeter()
{
return perimeter;
}
public int getSuperPerimeter()
{
return super.perimeter;
}
}
public class Polymorphism {
public static void main(String[] args)
{
shape s=new triangle();
print("s.perimeter:"+s.perimeter);
print("s.getperimeter:"+s.getPerimeter());
triangle t=new triangle();
print("t.perimeter:"+t.perimeter);
print("t.getperimeter:"+t.getPerimeter());
print("t.getsuperperimeter:"+t.getSuperPerimeter());
}
}
以下是運行結果:

這個運行結果包含了以下信息:
1.triangle對象向上轉型成shape后字段直接訪問都是由編譯器確定的,因此不會表現(xiàn)出多態(tài)性,返回的是1。
2.triangle對象向上轉型成shape后調用方法訪問字段是根據運行時對象類型延時綁定調用了triangle的getperimeter方法,返回的是3
3.t對象中包含了兩個perimeter字段,一個來自于他本身,一個來自于他的父類。同時用字段名去調用該字段時默認返回的是他本身的perimeter字段,要調用從父類繼承的該字段,要用super.perimeter的方法。
這個結果看起來多多少少讓人有些疑惑,為了避免這種情況出現(xiàn),我們一般都把字段聲明為private(子類就無法繼承),同時我們在子類中聲明的字段最好不要與從父類繼承的字段同名。
靜態(tài)方法是沒有多態(tài)性的,因為靜態(tài)方法是和類綁定的,不會存在不知道具體類型的情況。
構造函數的多態(tài)性?
構造函數是不具有多態(tài)性的,因為構造方法本身是靜態(tài)方法(如果不是的話,就會陷入雞生蛋,蛋生雞的死循環(huán)了)。要引入我們的問題,先來看一下構造函數的調用順序。
1.為這個對象分配的存儲空間都被初始化為0(對象初始化為null)
2.父類的構造函數調用(這樣才能保證在子類的構造函數中訪問的字段被初始化)
3.成員變量初始化
4.子類的構造函數調用
現(xiàn)在假設如果在第二步中,我們在父類的構造函數里調用了某個方法,這個方法是不是多態(tài)的?還是來看一個具體的例子:
class shape
{
protected int perimeter=1;
public shape()
{
draw();
print("shape created");
}
public void draw()
{
print("draw shape "+perimeter);
}
}
class triangle extends shape
{
int perimeter=3;
public triangle()
{
print("triangle created");
}
public void draw()
{
print("draw triangle "+perimeter);
}
public int getPerimeter()
{
return perimeter;
}
}
public class Polymorphism {
public static void main(String[] args)
{
shape s=new triangle();
}
}
運行結果:
我們可以看到雖然triangle對象還沒有構造完畢,draw方法仍是動態(tài)綁定到了triangle的draw方法。同時注意到perimeter的值還沒有初始化為3,而是0。
這樣的結果就是我們在triangle對象還沒有被初始化之前就訪問了其中的字段。因此我們在實際應用中要避免在構造函數中調用其他方法,或者只調用私有方法(不會被繼承,因此不會引發(fā)該問題)
相關文章
java swing實現(xiàn)電影購票系統(tǒng)
這篇文章主要為大家詳細介紹了java swing實現(xiàn)電影購票系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-01-01官方詳解HDFS?Balancer工具主要調優(yōu)參數
這篇文章主要為大家介紹了HDFS?Balancer工具主要調優(yōu)參數的?官方詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03Java案例使用比較排序器comparator實現(xiàn)成績排序
這篇文章主要介紹了Java案例使用比較排序器comparator實現(xiàn)成績排序,主要通過案例用TreeSet集合存儲多個學生信息,并遍歷該集合,要按照總分從高到低進行排序,下文介紹需要的朋友可以參考一下2022-04-04