第1条:考虑用静态工厂方法代替构造器
优势:
1. 静态工厂方法有名称。构造器只能与类名相同,而静态工厂方法名能取得更有意义。
2. 不必多次构建对象。
3. 可以返回原返回类型的任何子类型的对象。
4. 使代码更简洁。
构造器:Map<String, List<String>> m = new HashMap<String, List<String>>();
静态工厂:Map<Stirng, List<String>> m = HashMap.newInstance();
缺点:
1. 类如果不含 public 或 protect 的构造器,就不能被子类化。
2. 与其他静态方法实际上没有任何区别。
第2条:构造器有多个参数时要考虑用构建器
当遇到构造器有多个可选参数时,不使用重载构造器,而使用构建器:
public class User{
private final String account;
private final String password;
private final String name;
private final int age;
public static class Bulider{
//必要参数
private final String account;
private final String password;
//选填缺省参数值
private final String name = null;
private final int age = 0;
public Builder(String account, String password){
this.account = account;
this.password = password;
}
public Builder name(String val){
this.name = val;
return this;
}
public Builder age(int val){
this.age = val;
return this;
}
public User bulid(){
return new User(this);
}
}
private User(Builder builder){
account = builder.account;
password = builder.password;
name = builder.name;
age = builder.age;
}
}
使用时只要:
User user = new User.Builder("admin","123456")
.name("userName")
.age(20)
.build();
第3条:用私有构造器或者枚举类型强化Singleton属性
方法一:
public class Elvis{
//公有
public static final Elvis INSTANCE = new Elvis();
private Elvis(){...}
...
}
//调用
Elvis.INSTANCE;
方法二:
public class Elvis{
//私有
private static final Elvis INSTANCE = new Elvis();
private Elvis(){...}
public static Elvis getInstance(){
return INSTANCE;
}
...
}
//调用
Elvis.getInstance();
为防止客户端通过反射机制调用私用构造器,可以修改构造器,使其在被要求创建第二个是实例时,抛出异常。
另外,为了防止每次反序列化时都创建新实例,必须声明所有实例域都是瞬时的,并提供readResolve方法:
private Object readReslove(){
return INSTANCE;
}
方法三:
public class Elvis{
INSTANCE;
...
}
此方法是实现Singleton的最佳方法。(从java 1.5起可用。)它简洁,提供序列化机制,防止多次实例化。只需编写一个包含单个元素的枚举类型:
第4条:通过私有构造器强化不可实例化的能力
如果需要编写只有静态方法和静态域的类时,这种工具类是不希望被实例化,其实例化也没有意义的,而为了防止编译器添加默认构造器,只要让类包含私有构造器即可:
public class UtilityClass{
private UtilityClass(){ //私有构造器,防止该类被实例化
throw new AssertionError(); //创建对象即抛出错误
}
...
}
但这将使得该类不能被子类化,因为没有可以调用的超类构造器。
第5条:避免创建不必要的对象
除了重用不可变的对象之外,也可以重用那些已知不会被修改的可变对象。
String s = new String("abcdef"); //语句1,每次执行都创建新String实例 String s = "abcdef"; //语句2,每次执行都只使用同一个String实例
对于语句1,每次执行都将创建一个新的String实例,这是没必要的,因为“abcdef”本来就是String对象。
要优化使用基本数据类型而不是装箱基本类型,要当心无意识的自动装箱。
public static main(String[] args){ Long sum = 0L; for(long i = 0; i < Integer.MAX_VALUE; i++){ sum += i; //每次执行都会自动装箱,因为sum的类型是Long而不是long } System.out.printIn(sum); }
第6条:清理过期的对象引用
- 一个对象被无意识地保存起来,那么垃圾回收机制不仅不会处理该对象,也不会处理被该对象引用的其他对象。对性能造成潜在的重大影响。
- 清除过期引用最好的方法是让包含该引用的变量结束其生命周期。一旦程序不用某个对象引用就清空,这是没必要的。
- 除了自己管理内存的类(如Stack)外,内存泄露的另一个常见来源是缓存。(可用WeakHashMap。)
- 可以使用后台线程(Timer或ScheduledThreadPoolExecutor)或添加新条目时,进行缓存项的清理(如LinkedHashMap类的removeEldestEntry方法)。
- 内存泄露的第三个常见来源是监听器和其他回调。确保回调立即被当作垃圾回收的最佳方法是只保存他们的弱引用(weak reference)。
第7条:避免使用终结方法
- 终结方法通常是不可预测的,也是很危险的,会导致行为不稳定、降低性能,以及可移植性问题。一般情况下是不必要的。
- Java语言规范不仅不保证终结方法会被及时地执行,而且根本就不保证它们会被执行。
- 终结方法在不同的JVM平台上的运行表现可能截然不同。
- 可用显示的终止方法(如close(),cancel()等结合try-finally结构)来终结类的对象中封装的资源。
- “终结方法链”不会被自动执行,子类覆盖超类终结方法就必须手工调用超类终结方法。
除非作为安全网(对象所有者忘记调用显示终止方法),或则终止非关键的本地资源,否则不要使用终止方法。使用终结方法要记住调用super.finalize()。作为安全网,要记得记录终结方法的非法性(因为这表示客户端代码中的一个Bug)。如果需要把终结方法与公有的非final类关联起来,请考虑使用终结方法守卫者,一确保及时子类的终结方法未能调用super.finalize,该终结方法也会被执行。
public class Foo{ //该对象唯一目的是终止外围Foo对象 private final Object finalizerGuardian = new Object(){ @override protected void finalize() throws Throwable{ ...//终结外围Foo对象 } }; ... }