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 }
总之,公共类不该该暴露可变属性。 公共累暴露不可变属性的危害虽然仍然存在问题,但其危害较小。 然而,有时须要包级私有或私有内部类来暴露属性,不管此类是不是可变的。对象