Java中的靜態方法和實例方法的區別

一、程序方法層面的區別分析

靜態方法和實例方法的區別主要體現在兩個方面:

  • 在外部調用靜態方法時,可以使用”類名.方法名”的方式,也可以使用”對象名.方法名”的方式。而實例方法只有後面這種方式。也就是說,調用靜態方法可以無需創建對象。

  • 靜態方法在訪問本類的成員時,只允許訪問靜態成員(即靜態成員變量和靜態方法),而不允許訪問實例成員變量和實例方法;實例方法則無此限制。

下面幾個例子展示了這一區別:

1、調用靜態方法示例

//-----------hasStaticMethod.java-----------------
public class hasStaticMethod{
//定義一個靜態方法
    public static void callMe(){
      System.out.println("This is a static method.");
    }
}

下面這個程序使用兩種形式來調用靜態方法。
//-----------invokeStaticMethod.java-----------------
public class invokeStaticMethod{
  public static void main(String args[]){
      hasStaticMethod.callMe();  //不創建對象,直接調用靜態方法    
      hasStaticMethod oa = new hasStaticMethod();   //創建一個對象
      oa.callMe();      //利用對象來調用靜態方法
   }
} 

程序兩次調用靜態方法,都是允許的,程序的輸出如下:

This is a static method.This is a static method.

允許不創建對象而調用靜態方法,是Java爲了減少程序員調用某些常用方法時的麻煩,而允許程序員按照傳統的C語言中使用函數的方式來使用方法。典型的例子是前面某些程序中使用”Math.ramdon()”來獲取隨機數。還有一個很典型的代表就是數組的處理工具Arrays。

2、靜態方法訪問成員變量示例

//-----------accessMember.java-----------------
class accessMember{
    private static int sa; //定義一個靜態成員變量
    private int ia;  //定義一個實例成員變量
    //下面定義一個靜態方法
    static void statMethod(){
      int i = 0;    //正確,可以有自己的局部變量sa = 10;   
      //正確,靜態方法可以使用靜態變量
      otherStat();  
      //正確,可以調用靜態方法
      ia = 20;   //錯誤,不能使用實例變量
      insMethod();  //錯誤,不能調用實例方法
    }
    static void otherStat(){} 
    //下面定義一個實例方法 
    void  insMethod(){
      int i = 0;    //正確,可以有自己的局部變量
      sa = 15;    //正確,可以使用靜態變量
      ia = 30;    //正確,可以使用實例變量
      statMethod();   //正確,可以調用靜態方法
    }
} 

本例其實可以概括成一句話:靜態方法只能訪問靜態成員,實例方法可以訪問靜態和實例成員。之所以不允許靜態方法訪問實例成員變量,是因爲實例成員變量是屬於某個對象的,而靜態方法在執行時,並不一定存在對象。同樣,因爲實例方法可以訪問實例成員變量,如果允許靜態方法調用實例方法,將間接地允許它使用實例成員變量,所以它也不能調用實例方法。基於同樣的道理,靜態方法中也不能使用關鍵字this。

main()方法是一個典型的靜態方法,它同樣遵循一般靜態方法的規則,所以它可以由系統在創建對象之前就調用。

二、深入程序執行過程分析區別

Java程序啓動class文件被讀取時類被加載,如果有static方法,此時會分配內存,非static方法實例化類時纔在內存中分配控件存儲,引用存儲在堆棧中,實體存儲在堆中。
最大的區別在於內存。

靜態方法在程序開始時生成內存,實例方法在程序運行中生成內存,所以靜態方法可以直接調用,實例方法要先成生實例,通過實例調用方法,靜態速度很快,但是多了會佔內存。

任何語言都是對內存和磁盤的操作,至於是否面向對象,只是軟件層的問題,底層都是一樣的,只是實現方法不同。、

靜態內存是連續的,因爲是在程序開始時就生成了,而實例申請的是離散的空間,所以當然沒有靜態方法快,而且靜態內存是有限制的,太多了程序會啓動不了。

總結:
僅從代碼執行的角度來探討Java加載類、創建對象的過程,並沒有深入到JVM的機制中去。
1.一個對象第一次被創建時,先要加載該對象所屬的類,即對應的.class文件,當然如果類已經加載,再次創建該類的對象時,就不再需要重新加載類了。而一個類加載的時候,有三個部分需要加載,一個是靜態變量,再然後是靜態方法,然後是靜態初始化塊。(見到第一次執行結果就知道了,由於沒有創建實例所以初始化塊不執行)
2.然後開始創建該類的實例了,當然如果靜態方法跟靜態初始化對象中有對象的創建時,就繼續加載該對象的類,當然已經加載了該對象的類的話就不需要再次加載了。那麼對象實例的創建過程是什麼呢?首先是成員變量的引入,然後是實例初始化塊,之後纔是構造方法,構造方法執行完成之後纔算把這個對象給創建出來了。
在這個過程中,真正可以編寫執行代碼的地方有三個,靜態初始化、實例初始化以及構造方法。從以上的分析中我們可以看到,這三個代碼塊的執行順序是先類的靜態初始化,再實例初始化,最後執行構造方法。也就是說,靜態初始化是屬於類加載的過程,所以它只執行一次,而實例初始化是每個對象創建時都會執行一次,而構造方法跟實例初始化其實也差不多,不過它在實例初始化之後執行,而且構造方法可以重載多個,執行哪個構造方法是根據你的選擇來的。

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