前言
在編寫程序時不安全的初始化會導致程序發生發生重大錯誤。為了使程序可以被安全地初始化,C++引入了構造器(也可以成為構造方法)的概念,這是一個在創建對象時被自動調用的特殊方法。Java中也采用了構造器,並且提供了“垃圾回收器”。對不再使用的內存資源,垃圾回收器能自動將其釋放。本文下面主要介紹Java的構造方法以及匿名對象。
構造方法的定義語法與調用時機
構造方法的定義語法及訪問權限
構造方法是在創建對象時被編譯器自動調用,所以編譯器應該知道構造方法的名字然后去調用它,為構造方法任意取名都可能會與類的某個成員沖突。於是Java采用了同C++中一樣的方法:構造方法采用與類相同的名稱。
構造方法一般定義為如下三種方式:
class Student{
public Student(){ //①
...
}
...
}
class Student{
Student(){ //②
...
}
...
}
class Student{
private Student(){ //③
...
}
...
}
以上三種構造方式涉及到了訪問權限的問題:
第①種方式,構造方法采用了public修飾表示該類的對象是可以被不同包(package)的其他類創建。
第②種方式,默認為包訪問屬性,僅限於同包的類可以創建該類的對象。
第③種方式,使用private修飾使得構造方法對外不可見,無法在外部調用該類的構造器創建其實例。一般通過工廠模式創建該類實例。
以上列舉了三種訪問權限訪問修飾符,如果學過C++那舊還知道一種沒有出現的訪問權限修飾符就是protected。該修飾符表示本包中的類可訪問,不同包中的子類可以訪問。
對包做一個解釋:包類似於電腦中的文件夾,文件多了需要存於不同文件夾中方便管理,同樣如此,類多了就需要放在不同的包里面方便管理,同時也避免了命名沖突問題。
總結訪問權限修飾符的可訪問性:
范圍 | private | default(默認包訪問) | protected | public |
---|---|---|---|---|
同一個類 | O | O | O | O |
同一個包中的子類 | X | O | O | O |
同一個包中的其他類 | X | O | O | O |
不同包中的子類 | X | X | O | O |
不同包中的非子類 | X | X | X | O |
構造方法的調用時機(創建對象的初始化順序)
前面一直在說構造方法的調用是在類創建時,與普通方法不同,構造方法在實例化新對象(使用new開辟空間后)調用一次。普通方法在對象被實例化后可以調用多次。
由於對初始化有不同的需求,因此構造方法也可重載的。
下面跟蹤一下構造方法被調用的過程:
class Person{
private long pid=123456789;
public Person(){
System.out.println("Person()");
}
public Person(long pid){
System.out.println("Person(long pid)");
System.out.println("在使用傳進來的pid賦值前:pid:"+this.pid);
this.pid = pid;
System.out.println("在使用傳進來的pid賦值后:pid:"+this.pid);
}
}
public class Student extends Person{ //extends 實現繼承關系
private String name;
private int age=0;
public Student(){
System.out.println("Student()");
}
public Student(long pid, String name, int age){
super(pid); //調用父類的構造函數一定要寫在最前面不然會報錯
System.out.println("Student(long pid, String name, int age)");
this.name = name;
this.age = age;
}
public getName(){
return name;
}
public static void main(String[] args){
Student stu1 = new Student();
Student stu2 = new Student(123456,"Sakura",20);
}
}
/*
output:
Person()
Student()
Person(long pid)
在使用傳進來的pid賦值前:pid:123456789
在使用傳進來的pid賦值后:pid:123456
Student(long pid, String name, int age)
*/
可以輸出結果看出Java中的初始化順序如下:
- 在任何其他事情發生之前,首先會將分配給對象的存儲空間初始化成二進制零。
- 調用基類的構造函數。
- 按照聲明順序調用屬性的初始化方法。在Person中先將pid賦值為1234556789然后在返回到構造函數中將123456賦值給pid。
- 調用導出類的構造函數。若是Student中屬性有給定初始值,那么依舊如第三步后再進入構造函數進行其他初始化操作。
匿名對象
什么是匿名對象?
我們來看一步就創建對象的語法:
①類名稱 ②對象名稱 = ③new ④類名稱()
- ①:規定了對象的類型
- ②:對象的名字,唯一標識對象
- ③:開辟新的堆內存空間,存儲對象的內容
- ④:調用構造方法初始化對象
上面的這條語句在內存中開辟了兩個空間,一個棧空間存儲引用變量對象名稱,一個使用new開辟的堆空間用於存儲對象內容。
對象名稱指向了在對堆中的對象,於是我們可以使用對象名稱去操作對象
若是我們只有"new 類名稱();"這部分的話,那就是只是在堆中開辟了一個空間來保存對象信息,沒有棧去指向它。也就是這個空間是沒有名字的。所以簡單來說,沒有棧中引用指向的對象就叫做匿名對象。
匿名對象的使用
new Student(123456,"Sakura",20).getName();
由此就創建了一個匿名對象,可以向操作具名對象一樣操作它。
由於沒有引用變量指向匿名對象,所以只能使用一次,然后就會成為垃圾對象等待被GC回收,
小結
總結了Java中構造方法的定義和作用(為了在類對象實例化時設置屬性初始化)由此涉及到到類訪問權限,然后對類訪問權限做了一個小結,以及Java程序初始化的順序。最后介紹了匿名對象,即沒有棧中引用指向的對象。
參考:
[1] Eckel B. Java編程思想(第四版)[M]. 北京: 機械工業出版社, 2007