Java類初始化和例項化
Java有以下幾種方式建立類物件:
- 利用new關鍵字
- 利用反射Class.newInstance
- 利用Constructor.newIntance(相比Class.newInstance多了有參和私有建構函式)
- 利用Cloneable/Object.clone()
- 利用反序列化
Constructor.newInstance不支援帶原型入參的建構函式。
呼叫Class.getConstructor()方法獲取無參預設構造Constructor時,如果使用者自定義了有參建構函式,因為此時java並不會生成預設建構函式,所以Class.getConstructor()方法因找不到無參預設建構函式而拋異常。此時需要顯示定義預設建構函式:
// Initialization.java
public class Initialization {
private int age = 2000;
private int salary = age + 1000;
private String name = "Tom";
public Initialization() {
print();
}
public Initialization(Integer salary, String name) {
print();
this.salary = salary;
this.name = name;
print();
}
/**
* Static code
*/
{
salary += 500;
}
private void print() {
System.out.println("age=" + this.age);
System.out.println("salary=" + this.salary);
System.out.println("name=" + this.name);
}
public static Initialization construct(int salary, String name) throws Exception {
Constructor<Initialization> constructorWithNoParams = Initialization.class.getConstructor();
Constructor<Initialization> constructorWithParams = Initialization.class.getConstructor(Integer.class, String.class);
return salary <= 0 || name == null ? constructorWithNoParams.newInstance() : constructorWithParams.newInstance(salary, name);
}
public Initialization deSerialize() throws Exception {
// 寫物件
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("student.txt"));
output.writeObject(this);
output.close();
// 讀取物件
ObjectInputStream input = new ObjectInputStream(new FileInputStream("student.txt"));
return (Initialization) input.readObject();
}
}
再來看下Initialization類被編譯為.class檔案後的資訊:
public class Initialization {
private int age = 2000;
private int salary;
private String name;
public Initialization() {
this.salary = this.age + 1000;
this.name = "Tom";
this.salary += 500;
this.print();
}
public Initialization(Integer salary, String name) {
this.salary = this.age + 1000;
this.name = "Tom";
this.salary += 500;
this.print();
this.salary = salary.intValue();
this.name = name;
this.print();
}
private void print() {
System.out.println("age=" + this.age);
System.out.println("salary=" + this.salary);
System.out.println("name=" + this.name);
}
public static Initialization construct(int salary, String name) throws Exception {
Constructor constructorWithNoParams = Initialization.class.getConstructor(new Class[0]);
Constructor constructorWithParams = Initialization.class.getConstructor(new Class[]{Integer.class, String.class});
return salary > 0 && name != null?(Initialization)constructorWithParams.newInstance(new Object[]{Integer.valueOf(salary), name}):(Initialization)constructorWithNoParams.newInstance(new Object[0]);
}
public Initialization deSerialize() throws Exception {
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("student.txt"));
output.writeObject(this);
output.close();
ObjectInputStream input = new ObjectInputStream(new FileInputStream("student.txt"));
return (Initialization)input.readObject();
}
public static void main(String[] args) throws Exception {
Initialization result = construct(0, "Paul");
}
}
1、無論例項變數還是例項程式碼塊,均遵從先父類後子類的初始化順序。
2、對例項變數直接賦值或者利用例項程式碼塊賦值,編譯器會其程式碼填充到類的建構函式中。不允許書寫順序靠前的例項程式碼初始化在其後定義的例項變數。
Java強制要求Object物件(Object是Java的頂層物件,沒有超類)之外的所有物件建構函式的第一條語句必須是超類建構函式的呼叫語句或者是類中定義的其他的建構函式,如果我們既沒有呼叫其他的建構函式,也沒有顯式呼叫超類的建構函式,那麼編譯器會為我們自動生成一個對超類建構函式的呼叫。這樣確保當前物件完成初始化前其父類已完成初始化,從而構建完整的物件。
如果預設建構函式內部呼叫了有參建構函式,僅允許在有參建構函式裡呼叫父類建構函式。
靜態程式碼塊
- 多個static按編碼順序依次處理
- static變數的申明和初始化是兩個不同的操作
- static變數在編譯期已確認值
以下程式碼是等價的:
// code list1
public class StaticInitialization {
static {
data = 1;
}
public static void main(String[] args) {
System.out.println(data);
}
private static int data = 2;
}
// code list 2
public class StaticInitialization {
private static int data;
static {
data = 1;
data = 2;
}
public static void main(String[] args) {
System.out.println(data);
}
}
code list 2的位元組碼為:
public class StaticInitialization {
public StaticInitialization();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: getstatic #3 // Field data:I
6: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
9: return
static {};
Code:
0: iconst_1
1: putstatic #3 // Field data:I
4: iconst_2
5: putstatic #3 // Field data:I
8: return
}
可以看到static變數在編譯期就已放到常量const指向的記憶體地址裡。
初始化順序
如果沒有繼承關係,初始化順序為:靜態程式碼、靜態程式碼塊 > 成員變數、例項程式碼塊 > 建構函式。否則,初始化順序為先父後子。
所以初始化順序:父類static靜態變數 > 父類static程式碼塊 > 子類static靜態變數 > 子類static程式碼塊 > 父類變數 > 父類例項程式碼塊 > 父類建構函式 > 子類變數 > 子類例項程式碼塊 > 子類建構函式
舉個例子:
public class StaticTest {
public static void main(String[] args) {
staticFunction();
}
private static int data;
static StaticTest st;
static { //靜態程式碼塊
System.out.println("1");
}
{ // 例項程式碼塊
System.out.println("2");
}
static {
data = 1;
}
static {
st = new StaticTest();
}
StaticTest() { // 例項構造器
System.out.println("3");
System.out.println("a=" + a + ",b=" + b);
}
public static void staticFunction() { // 靜態方法
System.out.println("4");
}
int a = 110; // 例項變數
static int b = 112; // 靜態變數
}
/**
* 輸出結果
* 1
* 2
* 3
* a=110,b=0
* 4
*/
相關文章
- java中父類宣告子類例項化Java
- 關於類的初始化以及類的例項化一些思考
- 類和例項
- 類的例項化順序和分析
- python中類的建立和例項化Python
- python 類和例項Python
- Python中類建立和例項化過程Python
- Java--例項化Java
- Java子類和父類的初始化執行順序Java
- Dart - 抽象類的例項化Dart抽象
- ThinkPHP6 例項化 Http 類和依賴注入PHPHTTP依賴注入
- Python學習:類和例項Python
- 【Java面試高頻】i++和++i的區別,單例模式的多種實現以及區別,類和例項初始化順序,不看血虧Java面試單例模式
- java類初始化的順序Java
- Java中String類的初始化?Java
- Java類初始化執行流程Java
- vue 原始碼學習(二) 例項初始化和掛載過程Vue原始碼
- vue 原始碼學習(二) 例項初始化和掛載過程Vue原始碼
- JVM初探(五):類的例項化JVM
- python類例項化如何實現Python
- Vue 原始碼解析(例項化前) – 初始化全域性API(二)Vue原始碼API
- Vue 原始碼解析(例項化前) - 初始化全域性API(二)Vue原始碼API
- Vue 原始碼解析(例項化前) - 初始化全域性API(一)Vue原始碼API
- Vue 原始碼解析(例項化前) – 初始化全域性API(一)Vue原始碼API
- Vue 原始碼解析(例項化前) – 初始化全域性API(三)Vue原始碼API
- Vue 原始碼解析(例項化前) - 初始化全域性API(三)Vue原始碼API
- 好程式設計師Java培訓之類的例項化步驟程式設計師Java
- vue 快速入門 系列 —— Vue 例項的初始化過程Vue
- [短文速度-4] new子類是否會例項化父類
- Java介面為什麼不能例項化Java
- Java獲取Class物件的方式和例項化物件的方式Java物件
- java中String類常用方法的使用與例項Java
- 例項 靜態 類
- 關於java匿名內部類初始化法Java
- Java類什麼情況下被初始化?Java
- GObject學習筆記(一)類和例項GoObject筆記
- vue 原始碼解析(例項化前) - 初始化全域性 API(最終章)Vue原始碼API
- vue 原始碼解析(例項化前) – 初始化全域性 API(最終章)Vue原始碼API