java中類的初始化操作
java中一個類如果想要初始化,是如何進行的呢?砍了程式設計思想,也結合了網上其他人的文章,最終有了一個新的認識。
一、初始化順序
Java中類初始化順序:(靜態變數、靜態初始化塊)>(變數、初始化塊)>構造器。
其中小括號內部之間的呼叫順序是平行的,是按照程式碼的書寫順序來執行的。
二、靜態變數、靜態初始化塊的初始化操作
我們知道,靜態資料在記憶體中只佔用一份儲存空間。有幾點需要注意:
1、 static關鍵字不能應用於區域性變數中,也不能在構造方法裡面是宣告一個static關鍵字。
2、而且如果在使用之前沒有對其初始化,jvm會先對其有一個預設的初始化值。
3、如果他是一個物件引用,那麼他的預設初始化值就是null。
而靜態初始化塊,也是和靜態變數一樣,只執行一次。
static{
System.out.println("靜態塊");
}
三、變數、初始化塊
首先是變數,變數的初始化很簡單,其實概括起來也是幾句話
1、若資料型別是基本型別,當沒有在使用時進行初始化時,先有一個預設初始化值
2、區域性變數在使用時如果沒有初始化,則編譯時直接報錯、
3、一個類中含有物件,則在使用之前沒有初始化時,就會預設有一個值null(和靜態物件一樣)
接下來是初始化塊,先看一下初始化塊
{
System.out.println("花括號括起來的內容就是初始化塊");
}
1、其執行順序,與普通變數是並列的。根據在程式中書寫的前後順序來執行。
四、構造器的初始化
1、類的初始化的幾種方式:
1). 使用new關鍵字建立物件
這是我們最常見的也是最簡單的建立物件的方式,通過這種方式我們可以呼叫任意的建構函式(無參的和有參的)去建立物件。比如:
Student student = new Student();
2). 使用Class類的newInstance方法(反射機制)
我們也可以通過Java的反射機制使用Class類的newInstance方法來建立物件,事實上,這個newInstance方法呼叫無參的構造器建立物件,比如:
Student student2 = (Student)Class.forName("Student類全限定名").newInstance();
或者:
Student stu = Student.class.newInstance();
3). 使用Constructor類的newInstance方法(反射機制)
java.lang.relect.Constructor類裡也有一個newInstance方法可以建立物件,該方法和Class類中的newInstance方法很像,但是相比之下,Constructor類的newInstance方法更加強大些,我們可以通過這個newInstance方法呼叫有引數的和私有的建構函式,比如:
public class Student {
private int id;
public Student(Integer id) {
this.id = id;
}
public static void main(String[] args) throws Exception {
Constructor<Student> constructor = Student.class
.getConstructor(Integer.class);
Student stu3 = constructor.newInstance(123);
}
}
使用newInstance方法的這兩種方式建立物件使用的就是Java的反射機制,事實上Class的newInstance方法內部呼叫的也是Constructor的newInstance方法。
4). 使用Clone方法建立物件
無論何時我們呼叫一個物件的clone方法,JVM都會幫我們建立一個新的、一樣的物件,特別需要說明的是,用clone方法建立物件的過程中並不會呼叫任何建構函式。簡單而言,要想使用clone方法,我們就必須先實現Cloneable介面並實現其定義的clone方法,這也是原型模式的應用。比如:
public class Student implements Cloneable{
private int id;
public Student(Integer id) {
this.id = id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
public static void main(String[] args) throws Exception {
Constructor<Student> constructor = Student.class
.getConstructor(Integer.class);
Student stu3 = constructor.newInstance(123);
Student stu4 = (Student) stu3.clone();
}
}
5). 使用(反)序列化機制建立物件
當我們反序列化一個物件時,JVM會給我們建立一個單獨的物件,在此過程中,JVM並不會呼叫任何建構函式。為了反序列化一個物件,我們需要讓我們的類實現Serializable介面,比如:
public class Student implements Cloneable, Serializable {
private int id;
public Student(Integer id) {
this.id = id;
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
public static void main(String[] args) throws Exception {
Constructor<Student> constructor = Student.class
.getConstructor(Integer.class);
Student stu3 = constructor.newInstance(123);
// 寫物件
ObjectOutputStream output = new ObjectOutputStream(
new FileOutputStream("student.bin"));
output.writeObject(stu3);
output.close();
// 讀物件
ObjectInputStream input = new ObjectInputStream(new FileInputStream(
"student.bin"));
Student stu5 = (Student) input.readObject();
System.out.println(stu5);
}
}
6). 完整例項
public class Student implements Cloneable, Serializable {
private int id;
public Student() {
}
public Student(Integer id) {
this.id = id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
public static void main(String[] args) throws Exception {
System.out.println("使用new關鍵字建立物件:");
Student stu1 = new Student(123);
System.out.println(stu1);
System.out.println("\n---------------------------\n");
System.out.println("使用Class類的newInstance方法建立物件:");
Student stu2 = Student.class.newInstance(); //對應類必須具有無參構造方法,且只有這一種建立方式
System.out.println(stu2);
System.out.println("\n---------------------------\n");
System.out.println("使用Constructor類的newInstance方法建立物件:");
Constructor<Student> constructor = Student.class
.getConstructor(Integer.class); // 呼叫有參構造方法
Student stu3 = constructor.newInstance(123);
System.out.println(stu3);
System.out.println("\n---------------------------\n");
System.out.println("使用Clone方法建立物件:");
Student stu4 = (Student) stu3.clone();
System.out.println(stu4);
System.out.println("\n---------------------------\n");
System.out.println("使用(反)序列化機制建立物件:");
// 寫物件
ObjectOutputStream output = new ObjectOutputStream(
new FileOutputStream("student.bin"));
output.writeObject(stu4);
output.close();
// 讀取物件
ObjectInputStream input = new ObjectInputStream(new FileInputStream(
"student.bin"));
Student stu5 = (Student) input.readObject();
System.out.println(stu5);
}
}/* Output:
使用new關鍵字建立物件:
Student [id=123]
---------------------------
使用Class類的newInstance方法建立物件:
Student [id=0]
---------------------------
使用Constructor類的newInstance方法建立物件:
Student [id=123]
---------------------------
使用Clone方法建立物件:
Student [id=123]
---------------------------
使用(反)序列化機制建立物件:
Student [id=123]
*///:~
從Java虛擬機器層面看,除了使用new關鍵字建立物件的方式外,其他方式全部都是通過轉變為invokevirtual指令直接建立物件的。
2、類的構造器的執行過程
例項化一個類的物件的過程是一個典型的遞迴過程,如下圖所示。進一步地說,在例項化一個類的物件時,具體過程是這樣的:
在準備例項化一個類的物件前,首先準備例項化該類的父類,如果該類的父類還有父類,那麼準備例項化該類的父類的父類,依次遞迴直到遞迴到Object類。此時,首先例項化Object類,再依次對以下各類進行例項化,直到完成對目標類的例項化。具體而言,在例項化每個類時,都遵循如下順序:先依次執行例項變數初始化和例項程式碼塊初始化,再執行建構函式初始化。也就是說,編譯器會將例項變數初始化和例項程式碼塊初始化相關程式碼放到類的建構函式中去,並且這些程式碼會被放在對超類建構函式的呼叫語句之後,建構函式本身的程式碼之前。
程式碼實現一下:
第一步:定義爺爺類:
public class Grandpa {
Grandpa(){
System.out.println("爺爺類初始化,嘿嘿");
}
}
第二步:定義父類:
public class Father extends Grandpa {
Father(){
System.out.println("父類的初始化:");
}
}
第三步:定義子類:
public class Son extends Father{
Son(){
System.out.println("子類初始化");
}
public static void main(String[] args) {
Son son=new Son();
}
}
最後一步看結果:
從以上結果我們看到了類的執行過程。而在同一個類中構造器,是在最後執行的。
參考:https://blog.csdn.net/justloveyou_/article/details/72466416