JAVA編程思想(4),java編程思想

來源:互聯網
上載者:User

JAVA編程思想(4),java編程思想
若干個對象共用

  • 例如Frog對象擁有其自己的對象,並且知道他們的存活多久,因為Frog對象知道何時調用dispose()去釋放其對象。然而,如果這些成員對象中存在於其他一個或多個對象共用的情況,問題將不再簡單,不再能簡單的調用dispose()了。在這種情況下,我們也許需要引用計數來跟蹤依舊訪問著共用對象的數量。
//: polymorphism/ReferenceCounting.java// Cleaning up shared member objects.import static net.mindview.util.Print.*;class Shared {  private int refcount = 0;  private static long counter = 0;  private final long id = counter++;  public Shared() {    print("Creating " + this);  }  public void addRef() { refcount++; }  protected void dispose() {    if(--refcount == 0)      print("Disposing " + this);  }  public String toString() { return "Shared " + id; }}class Composing {  private Shared shared;  private static long counter = 0;  private final long id = counter++;  public Composing(Shared shared) {    print("Creating " + this);    this.shared = shared;    this.shared.addRef();  }  protected void dispose() {    print("disposing " + this);    shared.dispose();  }  public String toString() { return "Composing " + id; }}public class ReferenceCounting {  public static void main(String[] args) {    Shared shared = new Shared();    Composing[] composing = { new Composing(shared),      new Composing(shared), new Composing(shared),      new Composing(shared), new Composing(shared) };    for(Composing c : composing)      c.dispose();  }} /* Output:Creating Shared 0Creating Composing 0Creating Composing 1Creating Composing 2Creating Composing 3Creating Composing 4disposing Composing 0disposing Composing 1disposing Composing 2disposing Composing 3disposing Composing 4Disposing Shared 0*///:~
  • static long counter跟蹤所建立的Shared的執行個體的數量,id是final的,因為我們不希望它的值在對象生命週期中被改變。
  • 在將一個共用對象附著到類上時必須記住調用addRef(),但是dispose()方法跟蹤引用數,並決定何時執行清理。
構造器內部的多態方法行為
  • 如果在一個構造器的內部調用正在構造的對象的某個動態Binder 方法是會發生什嗎?
  • 在一般的方法內部,動態綁定的調用是在運行時才決定的,因為對象無法知道它是屬於方法所在的那個類,還是屬於那個類的匯出類。
  • 如果要調用構造器內部的一個動態Binder 方法,就要用到那個方法的被覆蓋後的定義。然而,這個調用效果可能相當難於預料,因為被覆蓋的方法在對象被完全構造之前就被調用。這可能會造成一些難於發現的錯誤。
  • 簡單來說就是在基類的構造器中調用基類中函數,這個函數也在匯出類中被覆蓋,當在匯出類調用基類構造器的時候,那麼因為一個動態綁定的方法調用會向外深入繼承階層內部,它可以調用匯出類裡的方法。那麼可能會調用某個方法,而這個方法所操作的成員可能還未進行初始化。
//: polymorphism/PolyConstructors.java// Constructors and polymorphism// don't produce what you might expect.import static net.mindview.util.Print.*;class Glyph {  void draw() { print("Glyph.draw()"); }  Glyph() {    print("Glyph() before draw()");    draw();    print("Glyph() after draw()");  }}    class RoundGlyph extends Glyph {  private int radius = 1;  RoundGlyph(int r) {    radius = r;    print("RoundGlyph.RoundGlyph(), radius = " + radius);  }  void draw() {    print("RoundGlyph.draw(), radius = " + radius);  }}    public class PolyConstructors {  public static void main(String[] args) {    new RoundGlyph(5);  }} /* Output:Glyph() before draw()RoundGlyph.draw(), radius = 0Glyph() after draw()RoundGlyph.RoundGlyph(), radius = 5*///:~
  • Glyph.draw()方法設計將會被覆蓋,這種覆蓋是在RoundGlyph中發生的。但是Glyph構造器會調用這個方法,結果導致了對RoundGlyph.draw()的調用,這似乎是我們的目的,但是輸出的結果卻不是我們預計的,我們發現當Glyph()的構造器調用draw()方法時,radius不是預設初始值1,而是0。
  • 我們先來看看初始化的實際過程:
    1. 在其他任何食物發生之前,將分配給對象的儲存空間初始化為二進位的零。
    2. 如以前說的一樣會調用基類構造器。此時,調用被覆蓋的draw()方法(要在調用RoundGlyph構造器之前調用),由於步驟1的緣故,我們此時會發現radius的值為0。
    3. 按照聲明的順序調用成員的初始化方法。
    4. 調用匯出類的構造器主體。
  • 這樣做有一個優點,那就是所有東西都至少初始化為零。而不是僅僅留作垃圾。對象的引用通常為null,所以如果忘記為該引用進行初始化,就會在運行時出現異常。
  • 因此,編寫構造器的時候有一條準則:“用儘可能簡單的方法使對象進入正常狀態,可以的話,避免調用其他方法。”在構造器唯一能夠安全調用的那些方法是基類中的final方法。
用繼承進行設計
  • 多態並不是用來使得任何東西都可以被繼承的,因為這反倒會加重我們的設計負擔,使事情變得不必要的複雜起來。
  • 更好的方式是選擇“組合”,尤其是不能十分確定應該使用哪一種方式時。組合更加靈活,因為它可以動態選擇類型(因此也就選擇了行為);相反,繼承在編譯時間需要知道確切類型。
//: polymorphism/Transmogrify.java// Dynamically changing the behavior of an object// via composition (the "State" design pattern).import static net.mindview.util.Print.*;class Actor {  public void act() {}}class HappyActor extends Actor {  public void act() { print("HappyActor"); }}class SadActor extends Actor {  public void act() { print("SadActor"); }}class Stage {  private Actor actor = new HappyActor();  public void change() { actor = new SadActor(); }  public void performPlay() { actor.act(); }}public class Transmogrify {  public static void main(String[] args) {    Stage stage = new Stage();    stage.performPlay();    stage.change();    stage.performPlay();  }} /* Output:HappyActorSadActor*///:~
  • 在這裡,Stage對象包含一個對Actor的引用,而Actor被初始化為HappyActor對象。這意味著performPlay()會產生某種特殊的行為。而當我們替換actor的對象引用的話,就可以改變我們的行為了。
  • 一條準則是:“用繼承表達行為的差異,並用欄位來表達狀態上的變化。”
純繼承與擴充
  • 採用“純粹”的方式("is-a")來建立繼承階層似乎是最好的方式。也就是說,只有基類已經建立的方法才可以在匯出類中被覆蓋。也可以說是匯出類“只有”覆蓋基類的函數沒有其他的函數。
  • 因為一個類的介面已經確定了它應該是什麼,繼承可以確保所有的匯出類具有基類的介面,且絕不會少。“純粹”的繼承,匯出類將具有和基類一樣的介面。
  • 也可以認為這是一種純替代,因為匯出類可以完全代替基類,而在使用它們時,可以不需要知道關於子類的任何額外資訊。也就是說,基類可以接收發送給匯出類的任何資訊,因為二者具有完全相同的介面。我們只需知道從匯出類向上轉型,永遠不需要知道正在處理的對象的確切類型。這都是通過多態來處理的。
  • 但是匯出類往往不是只單純的只具有從基類繼承的介面,它還有自己的額外函數,我們可以稱為是(is-like-a)(像一個)關係,因為匯出類就像是一個基類——它有著相同的介面,但是它還具有由額外方法實現的其他特性。
  • ”像一個“關係也是有缺點的。匯出類中介面的擴充部分不能被基類訪問。因此,一旦我們向上轉型,就不能調用那些新方法。在這種情況下,我們一般是重新查看對象的確切類型,以便我們能夠訪問該類型所擴充的方法。
向下轉型與運行時類型識別
  • 由於向上轉型會丟失具體的類型資訊,所以我們想,通過向下轉型來擷取類型資訊。然後我們知道向上轉型是安全的,因為基類的介面是不會大於匯出類的介面的。因此,我們通過基類的介面發送的資訊保證都能被接受。但是對於向下轉型,我們無法知道我們它將轉型是哪種類型。
  • 在Java中,所有轉型都會得到檢查!所以即使我們只是進行一次普通的加括弧形式的類型轉型,在進入運行時仍會進行檢查,如果不是正確的類型,會返回一個ClassCastException(類轉型異常)。這種在運行時期對類型進行檢查的行為稱作“運行時類型識別”(RTTI)。
//: polymorphism/RTTI.java// Downcasting & Runtime type information (RTTI).// {ThrowsException}class Useful {  public void f() {}  public void g() {}}class MoreUseful extends Useful {  public void f() {}  public void g() {}  public void u() {}  public void v() {}  public void w() {}}    public class RTTI {  public static void main(String[] args) {    Useful[] x = {      new Useful(),      new MoreUseful()    };    x[0].f();    x[1].g();    // Compile time: method not found in Useful:    //! x[1].u();    ((MoreUseful)x[1]).u(); // Downcast/RTTI    ((MoreUseful)x[0]).u(); // Exception thrown  }} ///:~

java編程思想第四版

你就在百度文庫裡面搜就行啊

這個是搜尋出來的結果
wenku.baidu.com/...0&od=0
 
java編程思想 第四版 中文版 紙質書與網上的電子書為何不一樣?

因為網上的JAVA編程思想第四版的電子書,大部分都是假的,只是第四版的封面加上了第三版的內容。你的紙質書是正確的,第七章是複用類,第八章是多態。我的紙質書跟你的一樣,放心吧。不過不明白為什麼第四版沒有了網路編程,不知道作者怎麼想的。我們捨得花錢買書,作者還捨不得紙張不成?不理解。
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.