1.清理
- 一個對象擁有自己的成員對象,並且知道他們應該存活多久,因此一個對象可以調用其特殊方法對其成員對象進行釋放。
然而,如果這些成員對象存在於其他一個或多個對象共享的情況,問題就複雜了,這個時候需要使用引用計數來跟蹤仍舊訪問着共享對象的對象數量。 - 下面的代碼可以清楚的說明這個問題的解決辦法,也是引用計數法
class Shared{ private int refcount = 0; private static long counter = 0; private final long id = counter ++; public Shared(){ System.out.println("Createing " + this); } //每有一個對象使用就調用這個方法進行加1, public void addRef(){ refcount ++; } protected void dispose(){ //如果共享這個對象都使用完了就清理這個類 if (--refcount == 0) { System.out.println("Disposiing" + this); } } } class Composing{ private Shared shared; private static long counter = 0; private final long id = counter ++; public Composing(Shared shared){ System.out.println("Createing " + this); this.shared = shared; this.shared.addRef(); } protected void dispose(){ System.out.println("disposing " + this); shared.dispose(); } public String toString(){return "Composing " + id;} } public class ReferenceCounting { public static void main(String[] args) { Shared shared = new Shared(); /** * shared被對個Composing共享,不能釋放一個Composiing就把這個shared對象給釋放了, * 這樣會報錯的,所以使用引用計數,只有到最後一個對象使用完畢後纔對shared進行釋放 */ Composing[] composing = { new Composing(shared), new Composing(shared), new Composing(shared), new Composing(shared), new Composing(shared) }; for (Composing c : composing) { c.dispose(); } } }
2.構造器內部的多態方法調用行爲
- 什麼意思呢,就是在一個父類的構造器內部調用其可以被子類重寫的方法,這一種特殊的情況
代碼如下
由上面代碼可以看出:由於集成過程中構造器的執行順序問題,在加上調用了可以被子類重寫的方法的問題的重合,只是輸出了我們意想不到的結果package com.yue.dt; class Glyph { // 可以被子類覆蓋的方法 void draw() { System.out.println("Glyph.draw()"); } Glyph() { System.out.println("Glyph() before draw()"); // 調用這個方法,如果子類覆蓋這個方法,那麼在聲明子類的時候回調用子類的這個方法 draw(); System.out.println("Glyph() after draw()"); } } class RoundGlyph extends Glyph { private int radius = 1; RoundGlyph(int r) { radius = r; System.out.println("RoundGlyph.RoundGlyph(),radius = " + radius); } void draw() { System.out.println("RoundGlyph.draw(), radius = " + radius); } } public class PolyConstructors { public static void main(String[] args) { new RoundGlyph(5);//聲明初始化子類 } } /** * 輸出結果 * Glyph() before draw() * RoundGlyph.draw(), radius = 0 調用了子類的方法 * Glyph() after draw() * RoundGlyph.RoundGlyph(),radius = 5 */
3.初始化的實際過程
- 在其他事物發生之前,將分配給對象的存儲空間初始化成二進制的零。
- 如前面那樣調用基類的構造器。此時調用覆蓋後的子類中draw()方法,在調用子類構造器之前調用,由於1,radius (int)被初始化成默認值0,
- 按照聲明的順序調用成員的初始化方法。
- 最後,調用子類的構造器中的代碼。
- 這樣做的好處是所有的東西都至少初始化爲0,其中通過“組合”嵌入進類內部的對象引用也被初始化爲null,使用這樣一個引用會拋出運行時異常。
- 怎樣解決上面的奇葩問題呢。
那就是不要在父類構造器中填寫可以被覆蓋的方法,如果要填寫方法,就填寫父類中private 或者final修飾的方法,儘量避免調用方法,儘可能的簡單