<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>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ### [構造器內部多態方法的行為](https://lingcoder.gitee.io/onjava8/#/book/09-Polymorphism?id=%e6%9e%84%e9%80%a0%e5%99%a8%e5%86%85%e9%83%a8%e5%a4%9a%e6%80%81%e6%96%b9%e6%b3%95%e7%9a%84%e8%a1%8c%e4%b8%ba) 構造器調用的層次結構帶來了一個困境。如果在構造器中調用了正在構造的對象的動態綁定方法,會發生什么呢? 在普通的方法中,動態綁定的調用是在運行時解析的,因為對象不知道它屬于方法所在的類還是類的派生類。 如果在構造器中調用了動態綁定方法,就會用到那個方法的重寫定義。然而,調用的結果難以預料因為被重寫的方法在對象被完全構造出來之前已經被調用,這使得一些 bug 很隱蔽,難以發現。 從概念上講,構造器的工作就是創建對象(這并非是平常的工作)。在構造器內部,整個對象可能只是部分形成——只知道基類對象已經初始化。如果構造器只是構造對象過程中的一個步驟,且構造的對象所屬的類是從構造器所屬的類派生出的,那么派生部分在當前構造器被調用時還沒有初始化。然而,一個動態綁定的方法調用向外深入到繼承層次結構中,它可以調用派生類的方法。如果你在構造器中這么做,就可能調用一個方法,該方法操縱的成員可能還沒有初始化——這肯定會帶來災難。 下面例子展示了這個問題: ~~~ // polymorphism/PolyConstructors.java // Constructors and polymorphism // don't produce what you might expect 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); } @Override 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 ~~~ **Glyph**的`draw()`被設計為可重寫,在**RoundGlyph**這個方法被重寫。但是**Glyph**的構造器里調用了這個方法,結果調用了**RoundGlyph**的`draw()`方法,這看起來正是我們的目的。輸出結果表明,當**Glyph**構造器調用了`draw()`時,**radius**的值不是默認初始值 1 而是 0。這可能會導致在屏幕上只畫了一個點或干脆什么都不畫,于是我們只能干瞪眼,試圖找到程序不工作的原因。 前一小節描述的初始化順序并不十分完整,而這正是解決謎團的關鍵所在。初始化的實際過程是: 1. 在所有事發生前,分配給對象的存儲空間會被初始化為二進制 0。 2. 如前所述調用基類構造器。此時調用重寫后的`draw()`方法(是的,在調用**RoundGraph**構造器之前調用),由步驟 1 可知,**radius**的值為 0。 3. 按聲明順序初始化成員。 4. 最終調用派生類的構造器。 這么做有個優點:所有事物至少初始化為 0(或某些特殊數據類型與 0 等價的值),而不是僅僅留作垃圾。這包括了通過組合嵌入類中的對象引用,被賦予**null**。如果忘記初始化該引用,就會在運行時出現異常。觀察輸出結果,就會發現所有事物都是 0。 另一方面,應該震驚于輸出結果。邏輯方面我們已經做得非常完美,然而行為仍不可思議的錯了,編譯器也沒有報錯(C++ 在這種情況下會產生更加合理的行為)。像這樣的 bug 很容易被忽略,需要花很長時間才能發現。 因此,編寫構造器有一條良好規范:做盡量少的事讓對象進入良好狀態。如果有可能的話,盡量不要調用類中的任何方法。在基類的構造器中能安全調用的只有基類的**final**方法(這也適用于可被看作是**final**的**private**方法)。這些方法不能被重寫,因此不會產生意想不到的結果。你可能無法永遠遵循這條規范,但應該朝著它努力。
                  <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>

                              哎呀哎呀视频在线观看