class類的初始化


class類的初始化##

 C++中引入了構造器這個概念(constructor)的概念,這是在創建一個對象時被自動調用的特殊方法。
 Java也引入了構造器
 構造器的主要的作用就是確保每個對象都會得到初始化。創建對象時,如果其類具有構造器,Java就會在用戶操作對象之前自動調用相應的構造器,從而確保初始化的進行。



public class Initial extends Parent {
	public static int i=j+1;
	public Initial()
	{
		System.out.println("1");
		System.out.println(i);
	}
	public  void get()
	{
		super.get();
		System.out.println("4");
	}
}
class Parent 
{
	public static int j=4;
	public Parent()
	{
		System.out.println("2");
	}
	public  void get()
	{
		System.out.println("3");
	}
}
...
public static void main(String[] args) {
		// TODO Auto-generated method stub
		Initial initial=new Initial();
		initial.get();
}
...

在上面類Initial和Parent類各有一個不帶參數的構造器,這可以保證在使用對象之前,已經被初始化了
 由於構造器和類名必須完全相同,所以不用在遵從方法首字母小寫的編碼風格

    Initial initial=new Initial();

 如果Initial()是Initial類的唯一的構造器,那么編譯器不會允許其他任何方式創建Initial對象。new Initial()會給相應的對象分配空間,並返回對新建對象的引用
 不帶任何參數的構造器被稱為默認構造器。

默認構造器###

 默認構造器又稱為無參構造器,它的作用是創建一個默認對象。如果類中沒有構造器,則編譯器會自動創建一個默認構造器。

public Bird(){} 
...
public static void main(String[] args) {
    Bird bird=new Bird();
}
...

如果已經定義了一個構造器(無論是否有參數),編譯器不會再自動創建默認構造器.意思就是,如果定義了構造器,那么只能用已經定義的構造器來構造對象,不能再使用默認構造器了。

繼承和初始化####

 在思考這個問題時,就要考慮到類的加載先后順序。Java的加載方式不同於C++。Java中的所有事物都是對象。每個類的編譯代碼都存在自己的獨立文件里。該文件只在需要使用程序代碼時才會被加載。一般來說,類的代碼在初次使用才會加載。這通常指的是加載發生於創建類的第一個對象,但是當訪問static域或static方法時,也會發生加載。(構造器是沒有顯式使用static的靜態方法),因此在使用構造器創建對象時就會加載類。
 運行最上面的代碼時,代碼的入是main()函數,由於main()函數是靜態函數,所以加載main函數所在的類的編譯代碼。接下來是Initial initial=new Initial();創建Initial對象,需要加載Initial類的編譯代碼(Initial.class).在對它進行加載的過程中編譯器會發現它有一個基類,於是繼續進行加載。如果該基類還有其他基類,則第二個基類就會被加載,如此類推,根基類的static初始化會被執行,然后是下一個導出類,以此類推。這種方式很重要,因為導出類的static的初始化可能會依賴基類成員能否被正確的初始化

類中成員的初始化###

 類加載的順序以及繼承類之間的static初始化順序現在清楚了,但是在一個類之中的初始化順序是怎么樣的?

class  Dogs
{
	int a;
	boolean b;
	char c;
	float f;
	double d;
	Dogs dogs;
	public void PrintInf()
	{
		System.out.println("a  "+a);
		System.out.println("b  "+b);
		System.out.println("c  "+c);
		System.out.println("d  "+d);
		System.out.println("dogs   "+dogs);
	}
	public Dogs(int i)
	{
		System.out.println("Dog("+i+")");
	}
	public Dogs()
	{
		
	}
}
class  Dogss{
	Dogs dogs=new Dogs(0);
	static Dogs dogs1=new Dogs(1) ;
	public Dogss()
	{
		System.out.println("Dogss()");
		dogs3=new Dogs(33);
	}
	static Dogs dogs2=new Dogs(2);
	static Dogs dogs3=new Dogs(3);
}
public class Dog {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Dogss dogss=new Dogss();
		new Dogs().PrintInf();
	}

}


運行結果
Dog(1)
Dog(2)
Dog(3)
Dog(0)
Dogss()
Dog(33)
a  0
b  false
c  
d  0.0
dogs   null
 

上面這些代碼可以看出
1、首先關於基本類型的初始化可以發現,在構造對象之后,基本類型數據成員都會首先初始化一個默認值,沒有自定義初始化的對象會默認為null。如上面的dogs被默認為null。
2、其次在類的內部,加載時首先是先初始化靜態變量,然后初始化正常對象(這里重點說明一下,不是static的基本類型變量,在沒有使用構造器創建對象時是沒有存儲位置的,所以也不會先於構造器初始化),然后調用構造器。就如同上面的結果一樣。先初始化了Dog(1),Dog(2),Dog(3),然后接下來是正常變量Dog(0),最后才是構造器
 加載類之后,先初始化靜態變量(對象和基本類型數據),接下來初始化正常創建的對象,(要使用構造器的話,因為只使用靜態參數的話是不需要使用構造器的)接下來調用構造器,初始化基本類型數據為默認值,調用自定義基本數據初始化方法,最后調用構造器里面的內容

總結一下對象的創建過程,假設有個名為Dog的類

1.即使沒有顯式使用static關鍵字,構造器也是靜態方法。因此當第一次創建Dog的對象時,或者Dog類的靜態方法被首次訪問時,Java解釋器就會加載Dog類,即尋找Dog.class文件

2.然后載入Dog.class文件,這是有關靜態初始化的所有動作都會執行(比如靜態變量被初始化,靜態對象的初始化,靜態方法的初始化)。因此靜態初始化只會在Class對象被首次加載的時候進行一次

3.當用new Dog()創建對象的時候,首先在堆上為Dog對象分配足夠的存儲空間。

4.這塊存儲空間現在為空,自動將Dog對象中的基本類型數據都設置為默認值,引用被設置為null

5.執行所有出現在字段定義出的初始化動作

6.執行構造器


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM