<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 6.3 組合與繼承的結合 許多時候都要求將組合與繼承兩種技術結合起來使用。下面這個例子展示了如何同時采用繼承與組合技術,從而創建一個更復雜的類,同時進行必要的構造器初始化工作: ``` //: PlaceSetting.java // Combining composition & inheritance class Plate { Plate(int i) { System.out.println("Plate constructor"); } } class DinnerPlate extends Plate { DinnerPlate(int i) { super(i); System.out.println( "DinnerPlate constructor"); } } class Utensil { Utensil(int i) { System.out.println("Utensil constructor"); } } class Spoon extends Utensil { Spoon(int i) { super(i); System.out.println("Spoon constructor"); } } class Fork extends Utensil { Fork(int i) { super(i); System.out.println("Fork constructor"); } } class Knife extends Utensil { Knife(int i) { super(i); System.out.println("Knife constructor"); } } // A cultural way of doing something: class Custom { Custom(int i) { System.out.println("Custom constructor"); } } public class PlaceSetting extends Custom { Spoon sp; Fork frk; Knife kn; DinnerPlate pl; PlaceSetting(int i) { super(i + 1); sp = new Spoon(i + 2); frk = new Fork(i + 3); kn = new Knife(i + 4); pl = new DinnerPlate(i + 5); System.out.println( "PlaceSetting constructor"); } public static void main(String[] args) { PlaceSetting x = new PlaceSetting(9); } } ///:~ ``` 盡管編譯器會強迫我們對基類進行初始化,并要求我們在構造器最開頭做這一工作,但它并不會監視我們是否正確初始化了成員對象。所以對此必須特別加以留意。 ## 6.3.1 確保正確的清除 Java不具備象C++的“析構器”那樣的概念。在C++中,一旦析構(清除)一個對象,就會自動調用析構器方法。之所以將其省略,大概是由于在Java中只需簡單地忘記對象,不需強行析構它們。垃圾收集器會在必要的時候自動回收內存。 垃圾收集器大多數時候都能很好地工作,但在某些情況下,我們的類可能在自己的存在時期采取一些行動,而這些行動要求必須進行明確的清除工作。正如第4章已經指出的那樣,我們并不知道垃圾收集器什么時候才會顯身,或者說不知它何時會調用。所以一旦希望為一個類清除什么東西,必須寫一個特別的方法,明確、專門地來做這件事情。同時,還要讓客戶程序員知道他們必須調用這個方法。而在所有這一切的后面,就如第9章(異常控制)要詳細解釋的那樣,必須將這樣的清除代碼置于一個`finally`從句中,從而防范任何可能出現的異常事件。 下面介紹的是一個計算機輔助設計系統的例子,它能在屏幕上描繪圖形: ``` //: CADSystem.java // Ensuring proper cleanup import java.util.*; class Shape { Shape(int i) { System.out.println("Shape constructor"); } void cleanup() { System.out.println("Shape cleanup"); } } class Circle extends Shape { Circle(int i) { super(i); System.out.println("Drawing a Circle"); } void cleanup() { System.out.println("Erasing a Circle"); super.cleanup(); } } class Triangle extends Shape { Triangle(int i) { super(i); System.out.println("Drawing a Triangle"); } void cleanup() { System.out.println("Erasing a Triangle"); super.cleanup(); } } class Line extends Shape { private int start, end; Line(int start, int end) { super(start); this.start = start; this.end = end; System.out.println("Drawing a Line: " + start + ", " + end); } void cleanup() { System.out.println("Erasing a Line: " + start + ", " + end); super.cleanup(); } } public class CADSystem extends Shape { private Circle c; private Triangle t; private Line[] lines = new Line[10]; CADSystem(int i) { super(i + 1); for(int j = 0; j < 10; j++) lines[j] = new Line(j, j*j); c = new Circle(1); t = new Triangle(1); System.out.println("Combined constructor"); } void cleanup() { System.out.println("CADSystem.cleanup()"); t.cleanup(); c.cleanup(); for(int i = 0; i < lines.length; i++) lines[i].cleanup(); super.cleanup(); } public static void main(String[] args) { CADSystem x = new CADSystem(47); try { // Code and exception handling... } finally { x.cleanup(); } } } ///:~ ``` 這個系統中的所有東西都屬于某種`Shape`(幾何形狀)。`Shape`本身是一種`Object`(對象),因為它是從根類明確繼承的。每個類都重新定義了`Shape`的`cleanup()`方法,同時還要用`super`調用那個方法的基類版本。盡管對象存在期間調用的所有方法都可負責做一些要求清除的工作,但對于特定的`Shape`類——`Circle`(圓)、`Triangle`(三角形)以及`Line`(直線),它們都擁有自己的構造器,能完成“作圖”(`draw`)任務。每個類都有它們自己的`cleanup()`方法,用于將非內存的東西恢復回對象存在之前的景象。 在`main()`中,可看到兩個新關鍵字:`try`和`finally`。我們要到第9章才會向大家正式引薦它們。其中,`try`關鍵字指出后面跟隨的塊(由花括號定界)是一個“警戒區”。也就是說,它會受到特別的待遇。其中一種待遇就是:該警戒區后面跟隨的`finally`從句的代碼肯定會得以執行——不管`try`塊到底存不存在(通過異常控制技術,`try`塊可有多種不尋常的應用)。在這里,`finally`從句的意思是“總是為`x`調用`cleanup()`,無論會發生什么事情”。這些關鍵字將在第9章進行全面、完整的解釋。 在自己的清除方法中,必須注意對基類以及成員對象清除方法的調用順序——假若一個子對象要以另一個為基礎。通常,應采取與C++編譯器對它的“析構器”采取的同樣的形式:首先完成與類有關的所有特殊工作(可能要求基類元素仍然可見),然后調用基類清除方法,就象這兒演示的那樣。 許多情況下,清除可能并不是個問題;只需讓垃圾收集器盡它的職責即可。但一旦必須由自己明確清除,就必須特別謹慎,并要求周全的考慮。 (1) 垃圾收集的順序 不能指望自己能確切知道何時會開始垃圾收集。垃圾收集器可能永遠不會得到調用。即使得到調用,它也可能以自己愿意的任何順序回收對象。除此以外,Java 1.0實現的垃圾收集器機制通常不會調用`finalize()`方法。除內存的回收以外,其他任何東西都最好不要依賴垃圾收集器進行回收。若想明確地清除什么,請制作自己的清除方法,而且不要依賴`finalize()`。然而正如以前指出的那樣,可強迫Java1.1調用所有收尾模塊(`Finalizer`)。 ## 6.3.2 名字的隱藏 只有C++程序員可能才會驚訝于名字的隱藏,因為它的工作原理與在C++里是完全不同的。如果Java基類有一個方法名被“重載”使用多次,在派生類里對那個方法名的重新定義就不會隱藏任何基類的版本。所以無論方法在這一級還是在一個基類中定義,重載都會生效: ``` //: Hide.java // Overloading a base-class method name // in a derived class does not hide the // base-class versions class Homer { char doh(char c) { System.out.println("doh(char)"); return 'd'; } float doh(float f) { System.out.println("doh(float)"); return 1.0f; } } class Milhouse {} class Bart extends Homer { void doh(Milhouse m) {} } class Hide { public static void main(String[] args) { Bart b = new Bart(); b.doh(1); // doh(float) used b.doh('x'); b.doh(1.0f); b.doh(new Milhouse()); } } ///:~ ``` 正如下一章會講到的那樣,很少會用與基類里完全一致的簽名和返回類型來覆蓋同名的方法,否則會使人感到迷惑(這正是C++不允許那樣做的原因,所以能夠防止產生一些不必要的錯誤)。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看