Tips
《Effective Java, Third Edition》一書英文版已經出版,這本書的第二版想必不少人都讀過,號稱Java四大名著之一,不過第二版2009年出版,到如今已經將近8年的時間,但隨着Java 6,7,8,甚至9的發佈,Java語言發生了深入的變化。
在這裏第一時間翻譯成中文版。供你們學習分享之用。java
有時候,你可能會試圖寫一些退化的類(degenerate classes),除了集中實例屬性以外別無用處:程序員
// Degenerate classes like this should not be public! class Point { public double x; public double y; }
因爲這些類的數據屬性能夠直接被訪問,所以這些類不提供封裝的好處(條目 15)。 若是不更改API,則沒法更改其表示形式,沒法強制執行不變量,而且在訪問屬性時沒法執行輔助操做。 堅持面向對象的程序員以爲這樣的類是厭惡的,應該被具備私有屬性和公共訪問方法的類(getter)所取代,而對於可變類來講,它們應該被替換爲setter設值方法:性能
// Encapsulation of data by accessor methods and mutators class Point { private double x; private double y; public Point(double x, double y) { this.x = x; this.y = y; } public double getX() { return x; } public double getY() { return y; } public void setX(double x) { this.x = x; } public void setY(double y) { this.y = y; } }
固然,對於公共類來講,堅持面向對象是正確的:若是一個類在其包以外是可訪問的,則提供訪問方法來保留更改類內部表示的靈活性。若是一個公共類暴露其數據屬性,那麼之後更改其表示形式基本上沒有可能,由於客戶端代碼能夠散佈在不少地方。學習
可是,若是一個類是包級私有的,或者是一個私有的內部類,那麼暴露它的數據屬性就沒有什麼本質上的錯誤——假設它們提供足夠描述該類提供的抽象。在類定義和使用它的客戶端代碼中,這種方法比訪問方法產生更少的視覺混亂。 雖然客戶端代碼綁定到類的內部表示,可是這些代碼僅限於包含該類的包。 若是類的內部表示是可取的,能夠在不觸碰包外的任何代碼的狀況下進行更改。 在私有內部類的狀況下,更改做用範圍進一步限制在封閉類中。this
Java平臺類庫中的幾個類違反了公共類不該直接暴露屬性的建議。 着名的例子包括java.awt包中的Point
和Dimension
類。 這些類別應該被視爲警示性的示例,而不是模仿的例子。 如條目 67所述,暴露Dimension
的內部結構的決定是一個嚴重的性能問題,這個問題在今天仍然存在。翻譯
雖然公共類直接暴露屬性並非一個好主意,可是若是屬性是不可變的,那麼危害就不那麼大了。當一個屬性是隻讀的時候,除了更改類的API外,你不能改變類的內部表示形式,也不能採起一些輔助的行爲,可是能夠增強不變性。例如,下面的例子中保證每一個實例表示一個有效的時間:code
// Public class with exposed immutable fields - questionable public final class Time { private static final int HOURS_PER_DAY = 24; private static final int MINUTES_PER_HOUR = 60; public final int hour; public final int minute; public Time(int hour, int minute) { if (hour < 0 || hour >= HOURS_PER_DAY) throw new IllegalArgumentException("Hour: " + hour); if (minute < 0 || minute >= MINUTES_PER_HOUR) throw new IllegalArgumentException("Min: " + minute); this.hour = hour; this.minute = minute; } ... // Remainder omitted }
總之,公共類不該該暴露可變屬性。 公共累暴露不可變屬性的危害雖然仍然存在問題,但其危害較小。 然而,有時須要包級私有或私有內部類來暴露屬性,不管此類是不是可變的。對象