JAVA語言特性筆記

1、JAVA支持的多態性質主要是爲兩種:靜態多分派和動態單分派。

  • 靜態多分派在JAVA中的表現形式即:重載。主要由靜態方法和私有方法構成(還有實例構造方法、父類方法)。他們的引用在類加載之初就已經被確定了。一個是類級別的,一個是私有方法,private訪問限定了它不能被子類訪問並覆寫。

  • 動態單分派的表現形式爲:覆寫(Override)
兩者的主要區別在於一個是編譯期綁定,一個是運行期綁定。這也是爲什麼靜態方法不能被覆寫只能被隱藏。
因爲靜態方法本身是不依靠類的實例而存在的,我們可以通過類名直接訪問它。看到一篇博文,覺得舉的例子非常恰當。
public class Client {  
    public static void main(String[] args) {  
         Base base = new Sub();  
         //調用非靜態方法  
         base.doAnything();  
         //調用靜態方法  
         base.doSomething();  
    }  
}  

class Base{  
    //父類靜態方法  
    public static void doSomething(){  
        System.out.println("我是父類靜態方法");
    }

    //父類非靜態方法  
    public void doAnything(){  
         System.out.println("我是父類非靜態方法");  
    }  
}  

class Sub extends Base{  
    //子類同名、同參數的靜態方法  
    public static void doSomething(){  
         System.out.println("我是子類靜態方法");  
    }  
    //覆寫父類的非靜態方法  
    @Override  
    public void doAnything(){  
         System.out.println("我是子類非靜態方法");  
    }  
}點擊打開鏈接
@來自http://www.cnblogs.com/DreamDrive/p/5428678.html


注意這裏的Base base=new Sub();這一行代碼,很明顯這是典型的使用派生類,使用了父類的引用指向子類的對象,向上轉型。其中,base的靜態類型是Base,這個在編譯期就已經確定,而實際類型Sub是在運行期才能確定的。

舉個例子,Sub繼承了父類Test,父類中有兩個重載方法,一個參數類型是Test,一個是Sub。這時候我們調用這個重載方法,將Test test=new Sub();傳入進去。前面我們提到了,靜態分派的典型應用是重載,而這個例子中test的靜態類型是Test,那麼答案應該是多少呢?




沒錯,就是調用了Test類型的重載方法。因爲重載是靜態分派,所以它的類型在編譯期就已經確定了,在確定使用哪一個重載方法的時候,是根據變量的靜態類型來確定的。


動態分派:

前面提到了JAVA的動態分派是動態單分派,即在執行覆寫的時候,只有一個宗量——參數。即參數是那個類型的,就覆寫了哪一個方法。


還是剛纔那個例子,只不過稍微改動了一下子類,添加了兩個方法, 和Test中一樣,一個靜態方法和一個實例方法。當傳入的類型是Sub時,調用了子類Sub中的test方法。

public class Test{
	public static String test(Test test){
		return "It's Test";
	}
	public String test(Sub sub){
		return "It's Sub";
	}
    public static void main(String[]args) {
    	Test test=new Sub();
    	Test test2=new Test();
    	Sub sub=new Sub();
    	System.out.println(test.test(sub));
    }
}
class Sub extends Test{
	public static String test(Test test){
		return "It's Sub Test";
	}
	public  String test(Sub sub){
		return "It's Sub Sub ";
	}
}
輸出:It's Sub Sub

靜態方法:

那麼如果傳入Test類型的參數呢?

System.out.println(test.test(test));


我們改動一下,將main方法中最後一句的參數改成test2,看看結果:    It's test



這次卻沒有覆寫父類的方法,調用的不再是子類中的test方法,而是父類中的方法,這是爲什麼呢?

這是因爲就像我們前面提到的,靜態方法和私有方法不能被覆寫,他們在編譯期就已經確定了類型,這時候又回到了最開始提到的靜態分派的過程中。

私有方法:

和靜態方法一樣,都不執行覆寫


類的成員變量:

在Test類和Sub類中, 分別加入public int i=1,=2;輸出test.i,結果1。

因爲類的成員變量也是一般的靜態分派。


基本數據類型==和包裝類型的equals()方法:

基本數據類型之間進行比較,低精度的會轉化成高精度的再進行比較。
如:
long a=12;
float f=12.0f;
    System.out.println(a==f);//輸出true 因爲f會先轉換成long類型 再進行數值的比較
而如果將其中一個改成包裝類型,在進行equals()方法比較,則會輸出false
因爲包裝類中的equals方法會先用instanceof關鍵字判定,被比較的對象是不是該類型或該類型的子類,很明顯Float不是Long類型的,或是它的子類,所以輸出false。
public boolean equals(Object obj) {
        if (obj instanceof Long) {
            return value == ((Long)obj).longValue();
        }
        return false;
    }
那如果改成Number類呢,我們知道Byte,Double, Float, Integer, Long, Short都是Number類的直接子類。
Long a=new Long(12);
        Number b=12;
        System.out.println(b.equals(a));//輸出false
結果還是false,因爲Number類的equals()方法是直接判定是否==


在方法參數中定義的final字段,可以應用在匿名內部類變量的使用上,比如Runnable的run方法,要求使用的字段是final的,這時候可以在上一級方法中定義的參數爲final型的,比如test(final String str){
 new Thread(new Runnable{
public void run(){
  
str="就是這樣";}

});
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章