1. 程式人生 > >謎題92:雙絞線

謎題92:雙絞線

構造 pre span void 而不是 字符串 方法 原因 做的

下面這個程序使用一個匿名類執行了一個並不自然的動作。它會打印出什麽呢?


public class Twisted {

    private final String name;

    Twisted(String name) {

        this.name = name;

    }

    private String name() {

        return name;

    }

    private void reproduce() {

        new Twisted("reproduce") {

            void printName() {

                System.out.println(name());

            }

        }.printName();

    }

    public static void main(String[] args) {

        new Twisted("main").reproduce();

    }

}

根據一個膚淺的分析會判斷該程序不能通過編譯。reproduce方法中的匿名類試圖調用Twisted類中的私有方法name。一個類不能調用另一個類的私有方法,是嗎?如果你試圖編譯這個程序,你會發現它可以成功地通過編譯。在頂層的類型(top-level type)中,即本例中的Twisted類,所有的本地的、內部的、嵌套的和匿名的類都可以毫無限制地訪問彼此的成員[JLS 6.6.1]。這是一個歡樂的大家庭。

在了解了這些之後,你可能會希望程序打印出reproduce,因為它在new Twisted(“reproduce”)實例上調用了printName方法,這個實例將字符串”reproduce”傳給其超類的構造器使其存儲到它的name域中。printName方法調用name方法,name方法返回了name域的內容。但是如果你運行這個程序,你會發現它打印的是main。現在的問題是它為什麽會做出這樣的事情呢?

這種行為背後的原因是私有成員不會被繼承[JLS 8.2]。在這個程序中,name方法並沒有被繼承到reproduce方法中的匿名類中。所以,匿名類中對於printName方法的調用必須關聯到外圍(“main”)實例而不是當前(“reproduce”)實例。這就是含有正確名稱的方法的最小外圍範圍(enclosing scope)(謎題 71和79)。

這個程序違反了謎題90中的建議:在”reproduce”中的匿名類即是Twisted類的內部類又擴展了它。單獨這一點就足以使程序難以閱讀。再加上調用超類的私有方法的復雜度,這個程序就成了純粹的冗長的廢話。這個謎題可以用來強調謎題6中的教訓:如果你不能通過閱讀代碼來分辨程序會做什麽,那麽它很可能不會做你想讓它做的事。要盡量爭取程序的清晰。

謎題92:雙絞線