使类和成员的可访问性最小化
实例域决不能是公有的。如果域是非final的,或者是指向可变对象的final引用,那么一旦是这个域编程共有的,就放弃了对存储在这个域中的值进行限制的能力;这意味着,你也放弃了强制这个域不可变的能力。同时,当这个域被又该的时候,你也市区了对它采取任何行动的能力。因此,包含公有可变域的类并不是线程安全的。
长度非零的数组总是可变的。
// Potential security hole!
public static final Thing[] VALUES = { ... };
有两种方法改善。
private static final Thing[] PRIVATE_VALUES = { ... };
public static final List<Thing> PRIVATE_VALUES =
Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
public static final Thing[] values() {
return PRIVATE_VALUES.clone();
}
在共有类中使用访问方法而非公有域
- 如果类可以在它所在的包外部进行访问,就提供访问方法。
- 如果类是包级私有的,或者是私有的嵌套类,直接暴露它的数据域并没有本质的错误。
- 如果域是不可变的,直接暴露域的危害比较小。
// 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 minutes;
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
}
使可变性最小化
不可变类:实例不能被修改的类。每个实例中包含的所有信息都必须在创建该实例的时候就提供,并在对象的整个生命周期内固定不变。
- 不提供任何会修改对象状态的方法;
- 保证类不会被扩展。一般做法是使这个类成为final的。
- 使所有的域都是final的。
- 使所有的域都成为私有的。
public final class Complex {
private final double re;
private final double im;
public Complex(double re, double im){
this.re = re;
this.im = im;
}
// Accessors with no coresponding mutators
public double realPart(){ return re; }
public double imaginaryPart() { return im; }
public Complex add(Complex c){
return new Complex(re + c.re, im + c.im);
}
public Complex substract(Complex c){
return new Complex(re - c.re, im - c.im);
}
// ...
}
- 不可变对象比较简单,它只有一种状态,即被创建时的状态。
- 不可变对象本质上是线程安全的,它们不要求同步。所以,不可变对象可以被自由的共享。所以,不可变类可以提供一些静态工厂,把频繁被请求的实例缓存起来,从而当现有实例可以符合请求的时候,就不必创建新的实例。
除了使用final修饰以外,还可以将类的所有构造器变成私有的或者包级私有,并添加公有的静态工厂。