Java 對象都是在堆中構造的。java
先看看 Employee 類的構造器:程序員
public class Employee { private String name; private double salary; private LocalDate hireDay; public Employee(String name, double salary, int year, int month, int day) { this.name = name; this.salary = salary; hireDay = LocalDate.of(year, month, day); } ... }
構造器與類同名。在構造 Employee 類的對象時,構造器會運行並初始化實例字段。ide
當使用下面這條代碼建立 Employee 類的實例時:
new Employee("James Bond", 100000, 1950, 1, 1);
將會把實例字段設置爲:函數
name = "James Bond"; salary = 100000; hireDay = LocalDate.of(1950, 1, 1); // 1950-01-01
有關構造方法,須要記住:ui
注意,不要在構造器中定義與實例字段同名的局部變量。例如:this
public Employee(String n, double s, int y, int m, int d) { String name = n; // 錯誤 double salary = s; // 錯誤 ... }
這個構造器聲明瞭局部變量 name 和 salary。這些變量只能在構造器內部訪問。這些變量會遮蔽同名的實例字段。有些程序員偶爾會不假思索地寫出這類代碼,由於它們的手指會不自覺地增長數據類型。這種錯誤很難檢查出來,所以,必須注意在全部方法中都不要使用與實例字段同名的變量。code
有些類有多個構造器。
new StringBuilder();
new StringBuilder("String");
這種功能叫作重載(overloading)。若是多個方法有相同的名字、不一樣的參數,便出現了重載。對象
Java 容許重載任何方法,而不僅是構造器方法。內存
編譯器必須挑選出具體調用哪一個方法,它用各個方法首部的參數類型與特定方法調用中所使用的值類型進行匹配,來選出正確的方法。若是編譯器找不到匹配的參數,就會產生編譯時錯誤,由於根本不存在匹配,或者沒有一個比其餘的更好。這個查找匹配的過程被稱爲重載解析(overloading resolution)。資源
要完整地描述一個方法,須要指出方法名以及參數類型。這叫作方法的簽名(signature)。例如,String 類有 4 個名爲 indexOf 的公共方法。它們的簽名是:
indexOf(int)
indexOf(int, int)
indexOf(String)
indexOf(String, int)
返回類型不是方法簽名的一部分。也就是說,不能有兩個名字相同、參數類型也相同卻有不一樣返回類型的方法。
不少類都包含一個無參數的構造器,由無參數構造函數建立對象時,其狀態會設置爲適當的默認值。例如,如下是無參數構造器:
public class Employee { private String name; private double salary; protected LocalDate hireDay; public Employee() { name = ""; salary = 0; hireDay = LocalDate.now(); } }
若是寫一個類時沒有編寫構造器,就會爲你提供一個無參數構造器。這個構造器將全部的實例字段設置爲默認值。因而,實例字段中的數值型數據設置爲 0、布爾型數據設置爲 false、全部對象變量將設置爲 null。
若是類中提供了至少一個構造器,可是沒有提供無參數的構造器,那麼構造對象時若是不提供參數就是爲不合法。
警告: 僅當類沒有任何其餘構造器的時候,纔會獲得一個默認的無參數構造器。編寫類的時候,若是寫了一個你本身的構造器,要想讓這個類的用戶可以經過如下調用構造一個實例:
new ClassName();
你就必須提供一個無參數的構造器,固然,若是但願全部的字段被賦予默認值,只須要提供如下代碼:
public ClassName() { }
在編寫很小的構造器時,經常在參數命名時感到困惑。
經常用單個字母做爲參數名:
public class Employee { ... public Employee(String n, double s) { name = n; salary = s; } }
但這樣作有一個缺點:只有閱讀代碼纔可以瞭解參數 n 和參數 s 的含義。
有些程序員在每一個參數前面加上一個前綴 「a」:
public class Employee { ... public Employee(String aName, double aSalary) { name = aName; salary = aSalary; } }
這樣很清晰。讀者一眼就能看懂參數的含義。
還有一種經常使用的技巧,它基於這樣的事實:參數變量會遮蔽同名的實例字段。若是將參數名命名爲 salary,salary 將指示這個參數,而不是實例字段。可是,仍是能夠用 this.salary 訪問實例字段。this 指示隱式參數,也就是所構造的對象。
public class Employee { ... public Employee(String name, double salary) { this.name = name; this.salary = salary; } }
關鍵字 this 指示一個方法的隱式參數。這個關鍵字還有另外一個含義。
若是構造器的第一個語句形如 this(...)
,這個構造器將調用同一個類的另外一個構造器。下面是一個典型的例子:
public class Employee { ... public Employee (double s) { // calls Employee(String, double) this("Employee #" + nextId, s); nextId++; } public Employee(String name, double salary) { this.name = name; this.salary = salary; } }
當調用 new Employee(6000)
時,Employee(double) 構造器將調用 Employee(name, double) 構造器。
採用這種方式使用 this 關鍵字很是有用,這樣對公共的構造器代碼只須要編寫一次便可。
因爲 Java 會完成自動的垃圾回收,不須要人工回收內存,因此 Java 不支持析構器。
某些對象使用了內存以外的其餘資源,例如,文件或使用了系統資源的另外一個對象的句柄。在這種狀況下,當資源再也不須要時,將其回收和再利用顯得十分重要。
若是一個資源一旦使用完就須要當即關閉,那麼應當提供一個 close 方法來完成必要的清理工做。能夠在對象用完時調用這個 close 方法。
若是能夠等到虛擬機退出,那麼能夠用方法 Runtime.addShutdownHook 增長一個 「關閉鉤」(shutdown hook)。在 Java 9 中,可使用 Cleaner 類註冊一個動做,當對象再也不可達時(除了清潔器還能訪問,其餘對象都沒法訪問這個對象),就會完成這個動做。在實際中這些狀況不多見。
警告: 不要使用 finalize 方法來完成清理。這個方法本來要在垃圾回收器清理對象以前調用。不過,你並不知道這個方法到底何時調用,並且該方法已經被廢棄。