1. 程式人生 > >final、static、代碼塊、靜態代碼塊、內部類、代碼執行順序

final、static、代碼塊、靜態代碼塊、內部類、代碼執行順序

調用 logs 構造代碼塊 tro 而且 classes phi println tina

final

final域使得確保初始化安全性(initialization safety)成為可能,初始化安全性讓不可變形對象不需要同步就能自由地被訪問和共享 作用在類上 則為final類,final類不能被繼承。一般用於工具類時,同時把工具類構造函數聲明為私有,暴露靜態共有方法 作用在成員變量上 則視為常量。此時賦值方式有三種:(1)聲明時賦值(2)構造函數中賦值(3)代碼塊中賦值。 即不管哪種方式都要保證在使用該變量之前要確保已經有值。使用該特性,可以強制賦值。final變量因為不可變,所以可以安全的存在於多線程中。 作用在方法上 作用在方法上可以保證該方法不能被重寫 作用在參數上
保證在方法體內部參數值不會被再次賦值,一般好的編程習慣應該把參數值視為final,不管有沒有顯示使用final(重構)

static

static關鍵字是隸屬於類而非對象。這也就意味著不管聲明了幾個對象,static關鍵字所修飾的空間只占用一份。改變了之後,所有的引用它的都會發生變化。靜態成員變量為所有類的對象共享。不像對象之間的變量是無影響的。所以對於static修飾的成員變量或者靜態代碼塊是在類加載的時候已經裝載。這種特性可以做一些初始化的工作而且保證只初始化了一次。 作用在包上import static(註意這裏不是static import com…..ClassName.*
靜態導包)這種以後再使用包裏面的靜態方法或者成員變量時會比較方便。eg:
import static java.lang.Integer.*;
int max_value = MAX_VALUE;
toHexString(max_value);
這樣就導入了Integer類下面所有的靜態方法和成員變量。在使用的時候就可以省去Integer,直接使用。 作用在類上 修飾類則為靜態類。只能作為靜態內部類,如果直接修飾類,則不能通過編譯。 作用在方法上 修飾方法則為靜態方法。靜態方法中不能使用非靜態變量。因為靜態方法中不能確定該方法是否有被初始化。但是非靜態方法可以引用靜態變量。 作用在變量上
作用在變量上則為靜態變量。靜態成員變量一般聲明為final的。因為隸屬於該類所有對象,可更改存在著危險。

代碼塊

代碼塊分為普通代碼塊和構造代碼塊 普通代碼塊:在方法或語句中出現的{},用的比較少。執行順序是按聲明順序執行。eg:
1 public static void main(String[] args) {
2         {
3             System.out.println("普通代碼塊-先聲明");
4         }
5         System.out.println("函數普通");
6         {
7             System.out.println("普通代碼塊-後聲明");
8         }
9     }
程序輸出結果如下:
普通代碼塊-先聲明
函數普通
普通代碼塊-後聲明
構造代碼塊:直接在類中定義且沒有static關鍵字的代碼塊,比較常用。執行順序是在構造函數執行之前執行,每聲明一個對象都會執行一次。
 1 public class CodeBlock {
 2     {
 3         System.out.println("構造代碼塊-先聲明-執行");
 4     }
 5     public CodeBlock(){
 6         System.out.println("構造器執行");
 7     }
 8     {
 9         System.out.println("構造代碼塊-後聲明-執行");
10     }
11     public void plainFunc(){
12         System.out.println("普通方法執行");
13     }
14     public static void main(String[] args) {
15         System.out.println("main方法");
16         CodeBlock cb1 = new CodeBlock();
17         cb.plainFunc();
18         CodeBlock cb2 = new CodeBlock();
19     }
20 }
程序輸出結果如下:
main方法
構造代碼塊-先聲明-執行
構造代碼塊-後聲明-執行
構造器執行
普通方法執行
構造代碼塊-先聲明-執行
構造代碼塊-後聲明-執行
構造器執行
結論: 執行順序:main方法->構造代碼塊->構造函數->普通方法
每實例化一個對象,則執行一次構造代碼塊

靜態代碼塊

在java中使用static關鍵字聲明的代碼塊。靜態塊用於初始化類,為類的屬性初始化。每個靜態代碼塊只會執行一次。由於JVM在加載類時會執行靜態代碼塊,所以靜態代碼塊先於主方法執行。 如果類中包含多個靜態代碼塊,那麽將按照"先定義的代碼先執行,後定義的代碼後執行"。 註意:1 靜態代碼塊不能存在於任何方法體內。2 靜態代碼塊不能直接訪問靜態實例變量和實例方法,需要通過類的實例對象來訪問。
 1 class Code{
 2     {
 3       System.out.println("Code的構造塊");
 4     }
 5     
 6     static{
 7         System.out.println("Code的靜態代碼塊");
 8         }
 9         
10     public Code(){
11         System.out.println("Code的構造方法");
12         }
13     }
14 public class CodeBlock{
15      {
16       System.out.println("CodeBlock的構造塊");    
17      }
18      
19      static{
20         System.out.println("CodeBlock的靜態代碼塊");
21         }
22         
23         public CodeBlock03(){
24              System.out.println("CodeBlock的構造方法");
25             }
26         
27       public static void main(String[] args){
28             System.out.println("CodeBlock的主方法");
29             new Code();
30             new Code();
31             new CodeBlock();
32             new CodeBlock();
33           }
34     }
程序輸出如下
CodeBlock的靜態代碼塊
CodeBlock的主方法 //這裏還沒有加載Code,所以先執行主方法,再執行Code的靜態代碼塊
Code的靜態代碼塊 
Code的構造塊
Code的構造方法
Code的構造塊
Code的構造方法
CodeBlock的構造塊
CodeBlock的構造方法

內部類

⒈成員內部類⒉靜態內部類⒊局部內部類⒋匿名內部類 定義 將一個類的定義放在另一個類的定義內部,這就是內部類 初見內部類 內部類的創建就和定義的一樣,把一個類定義在另一個類的內部(java語法規定一個類中只能有一個是public的,所以內部類不能用public修飾)
 1 public class Parcel2 {
 2   class Contents {
 3     private int i = 11;
 4     public int value() { return i; }
 5   }
 6   class Destination {
 7     private String label;
 8     Destination(String whereTo) {
 9       label = whereTo;
10     }
11     String readLabel() { return label; }
12   }
13   public Destination to(String s) {
14     return new Destination(s);
15   }
16   public Contents contents() {
17     return new Contents();
18   }
19   public void ship(String dest) {
20     Contents c = contents();
21     Destination d = to(dest);
22     System.out.println(d.readLabel());
23   }
24   public static void main(String[] args) {
25     Parcel2 p = new Parcel2();
26     p.ship("Tasmania");
27     Parcel2 q = new Parcel2();
28     // Defining references to inner classes:
29     Parcel2.Contents c = q.contents();
30     Parcel2.Destination d = q.to("Borneo");
31   }
32 }
這裏在類Parcel2中創建了兩個內部類Contents和Destination。同時每個內部類對應的創建了一個外部類方法,該方法用來返回一個指向內部類對象的引用。這種方式很常用!如果不提供指向內部類對象引用的函數,需要借助“.new”來創建內部類對象(後面會有用法)。如果想從外部類的非靜態方法之外的任意位置創建某個內部類對象,那麽必須像上述main()方法那樣,具體指明這個對象的類型:OutClassName.InnerClassName(eg:Parcel2.Contents),為什麽要這麽做呢? 註意:非靜態內部類對象有著指向外部類對象的引用。 這可以至少解釋兩個問題: 1、內部類擁有外部類的所有元素的訪問權(因為當生成內部類時內部類自動產生了指向外部類對象的引用,該引用可以訪問外部類的所有成員) 2、創建內部類對象時,需要指明對象類型,即: OutClassName out = new OutClassName(); OutClassName.InnerClassName=out.new InnerClassName(); 使用 .this 和 .new 如果需要生成對外部類對象的引用,可以使用外部類的名字後面緊跟原點和this。如果需要生成內部類對象,可以使用外部類對象後面緊跟原點和this。 外部類引用:
public class DotThis {
  void f() { System.out.println("DotThis.f()"); }
  public class Inner {
    public DotThis outer() {
      return DotThis.this;
      // A plain "this" would be Inner‘s "this"
    }
  }
  public Inner inner() { return new Inner(); }
  public static void main(String[] args) {
    DotThis dt = new DotThis();
    DotThis.Inner dti = dt.inner();
    dti.outer().f();
  }
}
註意:上面代碼DotThis.this返回外部類對象引用,如果直接使用this,則是內部類Inner對象引用,不能通過編譯。 創建內部類對象:
public class DotNew {
  public class Inner {}
  public static void main(String[] args) {
    DotNew dn = new DotNew();
    DotNew.Inner dni = dn.new Inner();
  }
}
內部類語法 一、成員內部類(非靜態): 1、可以訪問外部類所有元素 2、創建對象兩種方式:(1)在外部類中聲明方法返回內部類對象的引用(2)通過內部類對象後跟原點和new的方式(eg:DotNew dn = new DotNew(); DotNew.Inner dni = dn.new Inner();) 3、成員內部類中不能包含靜態數據(成員變量和方法) 二、靜態內部類: 1、不能訪問外部類的非靜態元素和方法。(因為靜態內部類沒有指向外部類對象的引用,只能直接通過類名來調用) 2、創建方式比較簡單
Outer.Inner inner = new Outer.Inner();
inner.func();
3、可以包含靜態數據 三、局部內部類 局部內部類就是可以定義在方法體內,比較少用 四、匿名內部類
interface content{
        int func();
    }
System.out.println(new content(){
            @Override
            public int func() {
                return 1;
            }
        }.func());
內部類優勢: 1、可以訪問外部類所有元素 2、隱藏性好,只有本類可操作 3、可以解決C++裏面的多繼承問題。怎麽解決? 我們知道,Java不支持多繼承(即一個類同時繼承兩個或多個類),只支持多重繼承(即A繼承B,B繼承C,那麽A間接繼承了C),利用Java的內部類機制可以做到多重繼承的效果。可以聲明多個內部類分別繼承相應的類,然後對於外部類來說,就同時擁有了相應內部類的功能。

代碼執行順序

1、父類靜態代碼塊->父類靜態成員變量初始化->子類靜態代碼塊->子類靜態成員變量初始化->(父類代碼塊->父類成員變量初始化)(這兩個誰先聲明誰在前面)->子類代碼塊->子類成員變量初始化->父類構造函數->子類構造函數->...
  • 靜態先於非靜態執行
  • 代碼塊可以當做成員變量來看,對於靜態代碼塊,類加載的時候執行;對於非靜態代碼塊,構造函數之前執行,可以想成是在成員變量初始化的時候執行
  • 父類優先於子類執行(因為子類涉及到對父類的重寫等操作,只有父類初始完畢了,子類重寫和引用才有意義)

參考文章:

1、《java編程思想》

2、http://www.cnblogs.com/sophine/p/3531282.html

final、static、代碼塊、靜態代碼塊、內部類、代碼執行順序