詳解java初始化順序
初始化
構造器初始化
自動初始化會在構造器呼叫之前發生
如:
public class Counter{
int i;
Counter(){
i=7;
}
}
那麼,i會被先初始化為0,然後在建構函式中賦值為7。對於所有的基本型別和物件引用,包括在定義時已經指定初值的變數,這種情況的成立的;因此,編譯器不會強制你一定要在構造器的某個地方或在使用他們之前對元素進行初始化—因為初始化早已得到了保證。但是區域性變數不會被初始化,java的措施是如果你使用了一個未初始化的變數,那麼將會報錯
。
初始化順序
在類的內部,變數定義的先後順序決定了初始化的順序。即使變數定義散步在方法定義之間,它仍舊會在任何方法(包括構造器)被呼叫之前得到初始化
package practice;
class window{
public window(int index) {
// TODO Auto-generated constructor stub
System.out.println("window"+index);
}
}
class House{
window w1=new window(1); //--------1
public House() {
// TODO Auto-generated constructor stub
System.out.println("House"); //---4
w3= new window(33); //--------5
}
window w2=new window(2); //--------2
void f() {
System.out.println("f()"); //------6
}
window w3=new window(3); //---------3
}
public class InitialSort {
public static void main(String args[]) {
House house=new House();
house.f();
}
}
output:
window1
window2
window3
House
window33
f ()
靜態初始化
package practice;
import javax.naming.event.NamingExceptionEvent;
class Bowl{
public Bowl(int mark) {
// TODO Auto-generated constructor stub
System.out.println("Bowl"+mark);
}
public void f1(int mark) {
System.out.println("f1("+mark+")");
}
}
class Table {
static Bowl bowl1=new Bowl(1);
public Table() {
// TODO Auto-generated constructor stub
System.out.println("Table()");
bowl1.f1(1);
}
static Bowl bowl2=new Bowl(2);
}
public class StaticInitialSort {
static Table table=new Table();
public static void main(String args[]) {
System.out.println("run main");
}
}
output:
Bowl1
Bowl2
Table()
f1(1)
run main
初始化的順序是先靜態物件,再非靜態物件。
分析輸出結果,因為這段程式碼要執行main()函式,所有必須要先載入StaticInitialSort
類,這時其靜態域table就會被初始化,導致Table類也會被載入進來,同理,Table類中的靜態域對應的類Bowl也會被載入進來。因此,在這個特殊的程式中,所有的類都會在main()方法執行前被載入到JVM中來,也就有了輸出結果中所顯示的資料。
總結一下物件的建立過程,假設由一個名為Dog的類:
- 即使沒有顯式地使用static關鍵字,構造器實際上也是靜態方法。因此,當首次建立類的物件或者使用類的靜態成員、方法時,JVM需要載入Dog類的class檔案。
- 載入Dog.class檔案後(實際上是建立了一個Class物件),有關靜態初始化的所有動作都會執行,因此,靜態初始化只在Class物件首次載入的時候執行一次。
- 當使用new Dog()建立物件時,首先會在堆上為Dog分配足夠的記憶體空間。
- 這塊儲存空間會被清零,這就自動地將Dog物件中地所有基本型別成員變數初始化為預設值,而引用則置為NULL。
- 執行所有出現於欄位定義處地初始化動作。
- 執行構造器。
例項初始化
package practice;
class Test{
{
System.out.println("例項");
}
public Test() {
// TODO Auto-generated constructor stub
System.out.println("call constructor");
}
}
public class 例項 {
public static void main(String args[]) {
Test Test1=new Test();
Test Test2=new Test();
}
}
例項
call constructor
例項
call constructor
例項程式碼塊和靜態程式碼塊地區別就是就是少了一個static,因此每new 一個物件都會執行例項程式碼塊,而靜態程式碼塊是在JVM載入class的時候執行的,只執行一次。
例項程式碼塊在匿名內部內中的初始化時是必須的,因為它沒法用建構函式初始化。
陣列的初始化
基本型別陣列的初始化
編譯器不允許指定陣列的大小,當定義一個數組
int a[];
此時擁有的只是這個陣列的一個引用(你已經為這個應用分配了足夠的儲存空間),但是沒有給陣列物件本身分配任何空間。
給陣列物件分配空間有兩種方式:
-
在建立陣列的時候分配:
int a[]={1,2,3,4,5};
-
使用初始化表示式
int a[]=new int[];
非基本型別的陣列
如果你建立了一個非基本型別陣列,那麼你建立的是一個引用陣列。以Integer為例子:
public class ArrayTest{
public static void main(String agrs[])
{
Integer a[]=new Integer[500];
for(int i=0;i<a.lenght;i++)
{
a[i]=Math.Random()*1000;
}
System.out.println(a.toArray());
}
}
在這裡,不像基本型別陣列一樣,即便使用new建立陣列之後,
Integer a[]=new Integer[500];
它也還是一個引用陣列,並且直到建立新的Integer物件,並把物件賦值個引用後,初始化過程才算結束:
a[i]=Math.Random()*1000;
還要其他的兩種初始化非基本型別陣列的方式:
Integer a[]={new Integer[10],new Integer[20],3};
Integer a[]=new Integer[]{new Integer[10],new Integer[20],3};