Java多態的使用注意事項_java

來源:互聯網
上載者:User

Java多態是如何?的?
Java的多態和C++一樣,是通過延時綁定(late binding)或者說運行時綁定(runtime binding)來實現的。當調用某一個對象引用的方法時,因為編譯器並不知道這個引用到底指向的是變數聲明時說明的類型對象,還是該類型子類的對象。因此編譯器無法為這次調用綁定到具體的某個方法。只有通過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多態中的一些陷阱

重寫私人方法?
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

欄位和靜態方法的多態?
子類可以繼承父類的非私人欄位,子類的欄位是否也具有多態性呢?我們來看一個實際的例子:

複製代碼 代碼如下:

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後欄位直接存取都是由編譯器確定的,因此不會表現出多態性,返回的是1。
2.triangle對象向上轉型成shape後調用方法訪問欄位是根據運行時物件類型延時綁定調用了triangle的getperimeter方法,返回的是3
3.t對象中包含了兩個perimeter欄位,一個來自於他本身,一個來自於他的父類。同時用欄位名去調用該欄位時預設返回的是他本身的perimeter欄位,要調用從父類繼承的該欄位,要用super.perimeter的方法。
這個結果看起來多多少少讓人有些疑惑,為了避免這種情況出現,我們一般都把欄位聲明為private(子類就無法繼承),同時我們在子類中聲明的欄位最好不要與從父類繼承的欄位同名。
靜態方法是沒有多態性的,因為靜態方法是和類綁定的,不會存在不知道具體類型的情況。

建構函式的多態性?
建構函式是不具有多態性的,因為構造方法本身是靜態方法(如果不是的話,就會陷入雞生蛋,蛋生雞的死迴圈了)。要引入我們的問題,先來看一下建構函式的調用順序。
1.為這個對象分配的儲存空間都被初始化為0(對象初始化為null)
2.父類的建構函式調用(這樣才能保證在子類的建構函式中訪問的欄位被初始化)
3.成員變數初始化
4.子類的建構函式調用

現在假設如果在第二步中,我們在父類的建構函式裡調用了某個方法,這個方法是不是多態的?還是來看一個具體的例子:

複製代碼 代碼如下:

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方法仍是動態綁定到了triangle的draw方法。同時注意到perimeter的值還沒有初始化為3,而是0。

這樣的結果就是我們在triangle對象還沒有被初始化之前就訪問了其中的欄位。因此我們在實際應用中要避免在建構函式中調用其他方法,或者只調用私人方法(不會被繼承,因此不會引發該問題)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.