1. 程式人生 > >7--黑馬程式設計師--技術總結之幾個重要的關鍵字

7--黑馬程式設計師--技術總結之幾個重要的關鍵字

、期待與您交流! ----------------------

一.static關鍵字

          static表示“全域性”或者“靜態”的意思,用來修飾成員變數和成員方法,也可以形成靜態static程式碼塊,但是Java語言中沒有全域性變數的概念。
        被static修飾的成員變數和成員方法獨立於該類的任何物件。也就是說,它不依賴類特定的例項,被類的所有例項共享。
        只要這個類被載入,Java虛擬機器就能根據類名在執行時資料區的方法區內定找到他們。因此,static物件可以在它的任何物件建立之前訪問,無需引用任何物件。 
        用public修飾的static成員變數和成員方法本質是全域性變數和全域性方法,當宣告它類的物件市,不生成static變數的副本,而是類的所有例項共享同一個static變數。
        static變數前可以有private修飾,表示這個變數可以在類的靜態程式碼塊中,或者類的其他靜態成員方法中使用(當然也可以在非靜態成員方法中使用),但是不能在其他類中通過類名來直接引用,這一點很重要。實際上你需要搞明白,private是訪問許可權限定,static表示不要例項化就可以使用,這樣就容易理解多了。static前面加上其它訪問許可權關鍵字的效果也以此類推。

       static修飾的成員變數和成員方法習慣上稱為靜態變數和靜態方法,可以直接通過類名來訪問,訪問語法為:
類名.靜態方法名(引數列表...)
類名.靜態變數名
       用static修飾的程式碼塊表示靜態程式碼塊,當Java虛擬機器載入類時,就會執行該程式碼塊。

         1、static變數(靜態變數)和例項變數
    按照是否靜態的對類成員變數進行分類可分兩種:一種是被static修飾的變數,叫靜態變數或類變數;另一種是沒有被static修飾的變數,叫例項變數。
兩者的區別是:
    對於靜態變數在記憶體中只有一個拷貝(節省記憶體),JVM只為靜態分配一次記憶體,在載入類的過程中完成靜態變數的記憶體分配,可用類名直接訪問(方便),當然也可以通過物件來訪問(但是這是不推薦的,會浪費記憶體)。
    對於例項變數,沒建立一個例項,就會為例項變數分配一次記憶體,例項變數可以在記憶體中有多個拷貝,互不影響(靈活)。
所以一般在需要實現以下兩個功能時使用靜態變數:
   1)在物件之間共享值時,即當類中的成員需要被所有物件共享時,用static修飾
   2)方便訪問變數時
程式碼示例:

  1. public class StaticDemo1 {  
  2.     /**分別通過類和物件來讀取靜態變數  
  3.      * @黑馬ZWF  
  4.      */  
  5.     public static void main(String[] args) {  
  6.         梯形 t = new 梯形(3.0f, 10.0f, 20);  
  7.         梯形.下底 = 200;        //通過類操作靜態變數  
  8.         System.out.println("梯形的下底為" + t.獲取下底() );  
  9.         t.修改下底(100);        //通過物件操作靜態變數  
  10.         System.out.println("梯形的下底為" + t.獲取下底() );  
  11.     }  
  12. }  
  13. class 梯形 {  
  14.     float 上底, 高;  
  15.     static float 下底;  
  16.     梯形(float x, float y, float h) {  
  17.         上底 = x;  
  18.         下底 = y;  
  19.         高 = h;  
  20.     }  
  21.     float 獲取下底 () {  
  22.         return 下底;  
  23.     }  
  24.     static void 修改下底(float b) {  
  25.         下底 = b;  
  26.     }  
  27. }  

         2.靜態方法
        類體中的方法分為例項方法和類方法兩種,用static修飾的是類方法。當一個類建立了一個物件後,這個物件就可以呼叫該類的方法。那麼例項方法和類方法有什麼區別呢?
        當類的位元組碼檔案被載入到記憶體時,類的例項方法不會被分配入口地址,當該類建立物件後,類中的例項方法才分配入口地址,從而例項方法可以被類建立的任何物件呼叫執行。需要注意的是,當建立第一個物件時,類中的例項方法就分配了入口地址,當再建立物件時,不再分配入口地址,也就是說,方法的入口地址被所有的物件共享,當所有的物件都不存在時,方法的入口地址才被取消。例項方法必須通過物件來呼叫,當某個物件呼叫例項方法時,該例項方法中出現的成員變數被認為是分配給該物件的成員變數,其中的類變數和其他物件共享,所以,例項方法既可以操作例項變數也可以操作類變數。
        對於類中的類方法,在該類被載入到記憶體時,就分配了相應的入口地址。從而類方法不僅可以被類建立的任何物件呼叫執行,也可以直接通過類名呼叫。類方法的入口地址直到程式退出才被取消。所以Java規定:類方法中出現的成員變數必須是被所有物件共享的變數(類變數),即類方法不可以操作例項變數,這樣規定的原因是:在類建立物件之前,例項成員變數還沒有分配記憶體。類方法也不可以呼叫其他的例項方法,這是因為在類建立物件之前,例項方法也沒有入口地址。
        無論是類方法或例項方法,當被呼叫執行時,方法中的區域性變數才被分配記憶體空間,方法呼叫完畢,區域性變數即刻釋放所佔的肉存。在一個方法被呼叫執行完畢之前,如果該方法又被呼叫,那麼,方法的區域性變數會再次被分配新的記憶體空間,比如,方法在遞迴呼叫時,方法中的區域性變數會再次被分配新的記憶體空間。在下面的程式碼示例中,我將通過遞迴呼叫類中的方法,計算出Fibinacii序列的第8項(Fibinacii序列的前兩項是1,後續每項的值都是該項的前兩項之和)

  1. public class StaticDemo2 {  
  2.     /**通過遞迴呼叫類中的方法,計算出Fibinacii序列的第8項  
  3.      * @黑馬ZWF  
  4.      */  
  5.     public static void main(String[] args) {  
  6.         // TODO Auto-generated method stub  
  7.         System.out.println("Fibinacii的第八項是" + Fibinacii.fibinacii(8));  //輸出結果是21  
  8.     }  
  9. }  
  10. class Fibinacii {  
  11.     public static int fibinacii(int n) {  
  12.         if (n == 1||n ==2)    //Fibinacii的前兩項都是1  
  13.             return 1;  
  14.         else   
  15.             return fibinacii(n - 1) + fibinacii(n - 2); //通過自身的遞迴呼叫fibinacii方法得出結果  
  16.     }  
  17. }  


二.this關鍵字

        this是Java的一個關鍵字,表示某個物件o this可以出現在例項方法和構造方法中,但不可以出現在類方法中。this關鍵字出現在類的構造方法中時,代表使用該構造方法所建立的物件。例項方法必須通過物件來呼叫,當this關鍵字出現在類的例項方法中時,代表正在呼叫該方法的當前物件。
        例項方法可以操作類的成員變數,當例項成員變數在例項方法中出現時,預設的格式為:
        this.成員變數
        當static成員變數在例項方法中出現時,預設的格式為:
        類名.成員變數
如:
  1. public class ThisDemo {  
  2.     int x;  
  3.     static int y;    //定義靜態變數y  
  4.     void f () {  
  5.         this.x=100;     //this.成員變數  
  6.         ThisDemo.y=200; //類名.成員變數  
  7.     }  
  8. }  

         在上述A類中的方法f中出現了this關鍵字,this代表使用方法f的當前物件。所以,this.x就表示當前物件的變數x,當物件呼叫方法f時,將100賦給該物件的變數x。因此,當一個物件呼叫方法時,方法中的例項成員變數就是指分配給該物件的例項成員變數,而static變數和其他物件共享。因此,通常情況下,可以省略例項成員變數名字前面的“this.”以及static變數前面的“類名.”。如:

  1. public class ThisDemo {  
  2.     int x;  
  3.     static int y;    //定義靜態變數y  
  4.     void f () {  
  5.         x=100;      //省略this關鍵字  
  6.         y=200;      //省略類名  
  7.     }         
  8. }  

       類的例項方法可以呼叫類的其他方法,對於例項方法呼叫的預設格式為:
       this.方法;
       對於類方法呼叫的預設格式為:
       類名.方法;
如:

  1. public class ThisDemo2 {  
  2.     void f () {  
  3.         this.g();   //this.方法名  
  4.         ThisDemo2.h(); //類名.方法名  
  5.     }  
  6.     void g(){  
  7.         System.out.println("ok") ;  
  8.      }  
  9.     static void h() {  
  10.         System.out.println("hello") ;  
  11.      }  
  12. }  

         在上述B類中的方法f中出現了this關鍵字,this代表使用方法f的當前物件。所以,方法f的方法體中this.g()就是當前物件呼叫方法g,也就是說,當某個物件呼叫方法f過程中,又呼叫了方法go由於這種邏輯關係非常明確,因此一個例項方法呼叫另一個方法時可以省略方法名字前面的“this.”或“類名.”。如:

  1. public class ThisDemo2 {  
  2.     void f () {  
  3.         g();   //省略this   
  4.         h();   //省略類名  
  5.     }  
  6.     void g(){  
  7.         System.out.println("ok") ;  
  8.      }  
  9.     static void h() {  
  10.         System.out.println("hello") ;  
  11.      }  
  12. }  

        注:this關鍵字不能出現在類方法中,這是因為,類方法可以通過類名直接呼叫。

三.final關鍵字

     final關鍵字可以修飾類、成員變數和方法巾的引數。
     final類不能被繼承,即不能有子類。如:
     final class A{ 
     ···
    )
        A就是一個final類。有時候是出於安全性的考慮,將一些類修飾為final類。例如:Java提供的String類,它對於編譯器和直譯器的正常執行有很重要的作用,對它不能輕易改變,
因此它被修飾為final類。
       如果一個方法被修飾為final方法,則這個方法不能被重寫。
       如果一個成員變數被修飾為final的,就是常量,常量必須賦給初值,而且不能再發生變化。
       如果方法的引數被修飾為final的,該引數的值不能被改變。
       在下面的程式碼示例中,A類中szetArea方法的引數r使用final修飾。這種邏輯關係非常明確,因此一個例項方法呼叫另一個方法時可以省略方法名字前面的“this.”或“類名.”。如:

  1. public class FinalDemo {  
  2.     public static void main(String[] args) {  
  3.         A a = new A();  
  4.         System.out.println("半徑為100的圓面積為:" + a.getArea(100));  
  5.     }  
  6. }  
  7. class A {  
  8.   //final double PI,   //非法,因為沒有給初值  
  9.     final double PI=3.1415926;// PI是常量且給定初值  
  10.     public double getArea(final double r) {    
  11.         //r=89;  非法,因為r已經被final修飾,不允許再改變r的值  
  12.         return PI *r * r;  
  13.     }  
  14. }