免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Java Puzzlers(5)更多類之謎

本章更多討論了子類對父類的繼承可能導致的各種陷阱,比如隱藏(hidden),遮蔽(shadow),遮掩(obscure),覆寫(override),重載(overload)等行為。

1。首先來看看一個隱藏的例子:

class Base {
    public String className = "Base";
}

class Derived extends Base {
    private String className = "Derived";
}

public class PrivateMatter {
    public static void main(String[] args) {
        System.out.println(new Derived().className);
    }
}

我們可能指望它打印Base,可很抱歉,此程序是無法編譯通過,剛一看錯誤信息你可能愣?。?/p>

無權訪問private的className。。。

對于實例方法,子類可以對父類的實例方法進行覆寫,可對于實例變量(而且包括類變量,靜態(tài)方法,final靜態(tài)變量),子類只能隱藏父類中的相同名稱的變量,而不是覆寫。根據newDerived()的編譯期類型為子類Derived,調用子類的className屬性,可此屬性是聲明為private的,所以無法編譯通過。如果我們想調用父類中被隱藏的className,可以通過向上轉型來實現:

System.out.println(((Base)new Derived()).className);

此例告訴我們,JAVA語言中子類定義與父類相同類型和名稱的變量、嵌套類型和靜態(tài)方法,都將隱藏掉父類中相應的方法,而不是覆寫,所以,請避免隱藏!此過程中當然也不存在所謂多態(tài)。另外,我們不應該違反這樣一條規(guī)則:對基類所做的任何行為,都應當可以同樣作用于子類。此例中子類className為private,違反了基類中className是public的定義,這樣的寫法應該避免。

 

2。也許哪一天你突然想自己寫一個String來代替java.lang中的String,讓我們來看看會發(fā)生什么?

public class StrungOut {
    public static void main(String[] args) {
        String s = new String("Hello world");
        System.out.println(s);
    }
}

class String {
    private final java.lang.String s;

    public String(java.lang.String s) {
        this.s = s;
    }

    public java.lang.String toString() {
        return s;
    }
}
試運行此程序,JVM會給你一個非常奇怪的消息:

StrungOut dose not have a main method!

怪了,明明有個main方法啊??請注意,main方法中的參數String []args,其中的String類型要求是java.lang.String,可JVM會自動地把把這些參數認為是我們自定義的下面那個String類型,這就是錯誤的原因所在。教訓:避免重用類名,特別是java平臺的類型,特別是java.lang包下的類名!在此例中,當前類所在包中的所有類的main方法都將因此失效。

3。遮掩(obscure):我覺的翻譯成模糊也許更好??纯聪旅娴睦樱?/p>

public class ShadesOfGray {
    public static void main(String[] args){
        System.out.println(X.Y.Z);
    }
}

class X {
    static class Y {
        static String Z = "Black";
    }

    static C Y = new C();
}

class C {
    String Z = "White";
}

你認為他應該打印什么呢??黑還是白?還是黑白不分:),光明的力量總是偉大,它一直打印的是:white。這說明了X.Y一直調用的是靜態(tài)變量Y,而不是靜態(tài)內隱類Y。JAVA語言規(guī)范告訴我們,當一個變量和一個類型具有相同的名字,明確他們位于相同的作用范圍內,變量名具有優(yōu)先權,同樣,變量名與類型名將遮掩包名。

即變量名>類型名>包名。其實上面的例子有更嚴重的問題,它并沒有遵循標準的JAVA命名習慣,變量應該以小寫開頭(mixedCase的格式),類名以大寫開頭(MaxedCase的格式),如果完全遵照習慣來寫,就不會出現此問題了。所以,請遵守標準的命名習慣。退一步,假設在某些情況下我們只能以此方式書寫,那我們怎么訪問靜態(tài)內隱類Y呢?兩種方法:

System.out.println(((X.Y)null).Z);   //借助表達式訪問類變量,還記的嗎?

在JDK5中還可以這樣:

public static <T extends X.Y> void main(String args[]){     //繼承X.Y類解決此問題。

            System.out.println(T.Z);

 }   

 

4。包A中的某個類被另一個包C中的子類所繼承,如果子類當中“覆寫”了父類中的方法,而此方法在父類中不是聲明為public或者protected,那么這并非覆寫,這兩個方法將沒有任何關系。所以,如果你希望某個類的一個方法被包外的子類所覆寫,請把此方法聲明為protected或者public。

5。遮蔽(shadow),這里討論了JDK5靜態(tài)導入需要注意的問題,看下面的例子:

import static java.util.Arrays.toString;

class ImportDuty {
    public static void main(String[] args) {
        printArgs(1, 2, 3, 4, 5);
    }

    static void printArgs(Object... args) {
        System.out.println(toString(args));
    }
}
這個例子表面上看起來很正常,可事實上是無法編譯通過的,編譯器告訴我們,找不到恰當的toString()方法。這是為何?我們明明已經導入了Arrays.toString方法了啊?應該打印:[1,2,3,4,5]才對!這是因為編譯器將首先在類ImportDuty的范圍內尋找toString方法,這個方法將從Object類繼承而來的toString()方法,它并不能接受參數Object []args!這就是原因所在,某個范圍內的成員對比于靜態(tài)導入的具有優(yōu)先權。也就是類ImportDuty的toString()方法遮蔽了Arrays.toString(Object []args)方法。遮蔽與遮掩的區(qū)別在于,遮蔽的只能是同類型的名稱,而遮掩的是不同類型的(如變量名遮掩類名,類名遮掩包名)。慎重使用靜態(tài)導入。

6。最后一個謎題很重要哦,我現在才知道JDK5對條件操作符(a?b:c)已經有重大改變。試著分別在JDK1.4和JDK5中運行下面的程序:

import java.util.Random;

public class CoinSide {
    private static Random rnd = new Random();

    public static CoinSide flip() {
        return rnd.nextBoolean() ?
            Heads.INSTANCE : Tails.INSTANCE;
    }

    public static void main(String[] args) {
        System.out.println(flip());
    }
}

class Heads extends CoinSide {
    private Heads() { }
    public static final Heads INSTANCE = new Heads();

    public String toString() {
        return "heads";
    }
}

class Tails extends CoinSide {
    private Tails() { }
    public static final Tails INSTANCE = new Tails();

    public String toString() {
        return "tails";
    }
}
發(fā)現了嗎?在jdk1.4及以前版本當中,此程序無法通過,報錯:

incompatible types for ?: neither is a subtype of the other

說什么第2個操作數和第3個操作數都不是另外一個子類。而在JDK5下這個程序將正常運行,隨機打印heads或者tails。這是因為在JDK5以前,條件運算符要求:當第2個和第3個操作數是引用類型時,它們其中的一個必須是另外一個的子類。而例子中Heads和Tails都不是對方的子類,所以產生了上面的錯誤。而在JDK5中,這個條件放寬了,第2個和第3個操作數如果是引用那么都是合法的,只不過其結果類型將是這兩種類型的最小公共超類。此例中Heads和Tails的超類向上追溯有CoinSide,Object,而CoinSide是他們的最小公共超類。

如果想在JDK5以前運行上面的程序,可以把第2或者第3操作數向上轉型為他們的超類即可:

   public static CoinSide flip() {
        return rnd.nextBoolean() ?
            (CoinSide)Heads.INSTANCE : Tails.INSTANCE;
    }

另外一些謎題討論了對Object類中方法的覆寫問題,特別要注意不要覆寫變成了重載



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=728172

本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現有害或侵權內容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Java接口 詳解(二)
最全的Java筆試題庫之選擇題篇-總共234道【1~60】
Java FAQ(新手必看)
一些JavaSE學習過程中的思路整理(一)(主觀性強,持續(xù)更新中...)
java---- 封裝,接口,繼承,覆蓋,構造過程,多態(tài),static、this、super、final用法
數組
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯系客服!

聯系客服