Java final 類和方法(學習 Java 編程語言 041)

不容許擴展的類被稱爲 final 類。若是在定義類的時候使用了 final 修飾符就代表這個類是 final 類。java

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence,
               Constable, ConstantDesc {
    ...
}

類中的某個特定方法也能夠被聲明爲 final。若是這樣作,子類就不能覆蓋這個方法(final 類中的全部方法自動地成爲 final 方法)。程序員

public class Employee
{
    ...
    public final String getName()
    {
        return name;
    }
    ...
}

字段也能夠被聲明爲 final。對於 final 字段來講,構造對象以後就不容許改變它們的值了。不過,若是將一個類聲明爲 final,只有其中的方法自動地成爲 final,而不包括字段。ide

將方法或類聲明爲 final 主要目的是: 確保它們不會在子類中改變語義。例如:優化

  • Calendar 類中的 getTime 和 setTime 方法都聲明爲 final。這代表 Calendar 類的設計者負責實現 Date 類與日曆狀態之間的轉換,而不容許子類來添亂。
  • String 類也是 final 類,這意味着不容許任何人定義 String 的子類。換言之,若是有一個 String 的引用,它引用的必定是一個 String 對象,而不多是其餘類的對象。

有些程序員認爲:除非有足夠的理由使用多態性,不然應該將全部的方法都聲明爲 final。事實上,在 C++ 和 C# 中,若是沒有特別地說明,全部的方法都不具備多態性。這兩種作法可能都有些偏激。咱們提倡在設計類層次時,要仔細地思考應該將哪些方法和類聲明爲 final。設計

在早期的 Java 中,有些程序員爲了不動態綁定帶來的系統開銷而使用 final 關鍵字。若是一個方法沒有被覆蓋而且很短,編譯器就可以對它進行優化處理,這個過程稱爲內聯(inlining)。例如,內聯調用 e.getName() 將被替換爲訪問字段 e.name。這是一項頗有意義的改進,CPU 在處理當前指令時,分支會擾亂預取指令的策略,因此,CPU 不喜歡分支。然而,若是 getName 在另一個類中被覆蓋,那麼編譯器就沒法知道覆蓋的代碼將會作什麼操做,所以也就不能對它進行內聯處理了。code

幸運的是,虛擬機中的即時編譯器比傳統編譯器的處理能力強得多。這種編譯器能夠準確地知道類之間的繼承關係,並可以檢測出是否有類確實覆蓋了給定的方法。若是方法很簡短、被頻繁調用並且確實沒有被覆蓋,那麼及時編譯器就會將這個方法進行內聯處理。若是虛擬機加載了另外一個子類,並且這個子類覆蓋了一個內聯方法,那麼將會發生什麼狀況呢?優化器將取消這個方法的內聯。這個過程很慢,不過不多會發生這個狀況。對象

相關文章
相關標籤/搜索