1> 考虑用静态工厂方法代替构造器
3> 用私有构造器或者枚举类型强化Singleton属性
2> 公有的成员是个静态工厂方法
5> 避免创建不必要的对象
1> 要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱
这段代码中会无意识中创建大量多余的Long实例,将sum的声明从Long改成long会是性能得到提升。
静态工厂方法的好处:
1> 有名称 -> 可以根据静态工厂方法的类型构造不同的名称,更易于阅读
2> 不必在每次调用它们的时候都创建一个新对象 -> 单例、享元模式
3> 可以返回原返回类型的任何子类型的对象 -> EnumSet
4> 简化代码 -> eg, HashMap.newInstance() 替代 new HashMap()
缺点:
1> 类如果不含公有的或者受保护的构造器,就不能被子类化
2> 与其他的静态方法实际上没有区别。-> 遵守标准的命名习惯: valueOf / of / getInstance / newInstance / getType / newType
2> 遇到多个构造器参数时要考虑用构建器
e.g
package com.chal.builder1;
/**
* @author Chal Nan
*/
public class NutritionFacts {
private int arg1;
private int arg2;
private int arg3;
public static class NutritionBuilder implements Builder<NutritionFacts> {
private int arg1;
private int arg2;
private int arg3;
public NutritionBuilder setArg1(int arg1) {
this.arg1 = arg1;
return this;
}
public NutritionBuilder setArg2(int arg2) {
this.arg2 = arg2;
return this;
}
public NutritionBuilder setArg3(int arg3) {
this.arg3 = arg3;
return this;
}
@Override
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
public NutritionFacts(NutritionBuilder builder) {
this.arg1 = builder.arg1;
this.arg2 = builder.arg2;
this.arg3 = builder.arg3;
}
@Override
public String toString() {
return "NutritionFacts{" +
"arg1=" + arg1 +
", arg2=" + arg2 +
", arg3=" + arg3 +
'}';
}
public static void main(String[] args) {
NutritionFacts nutritionFacts = new NutritionBuilder().setArg1(1).setArg2(2).setArg3(3).build();
System.out.println(nutritionFacts);
}
}
package com.chal.builder1;
/**
* Created by Chal Nan on 6/30/14.
*/
public interface Builder<T> {
T build();
}
3> 用私有构造器或者枚举类型强化Singleton属性
1> 公有静态成员是个final域
package com.chal.singleton;
/**
* Created by Chal Nan on 7/20/14.
* SuccessFactors.
*/
public class Singleton1 {
public static final Singleton1 INSTANCE = new Singleton1();
private Singleton1() {
}
}
Note: 享有特权的客户端可以借助AccessibleObject.setAccessible 方法通过反射机制调用私有构造器。
package com.chal.singleton;
/**
* Created by Chal Nan on 7/20/14.
* SuccessFactors.
*/
public class Singleton2 {
private static final Singleton2 INSTANCE = new Singleton2();
private Singleton2() {
}
public Singleton2 getInstance() {
return INSTANCE;
}
}
3> 编写一个包含单个元素的枚举类型
package com.chal.singleton;
/**
* Created by Chal Nan on 7/20/14.
* SuccessFactors.
*/
public enum Singleton3 {
INSTANCE;
// method...
}
单元素的枚举类型已经成为实现Singleton的最佳方法。
4> 通过私有构造器强化不可实例化的能力
5> 避免创建不必要的对象
e.g
String s = new String("test") // DON'T DO THIS !
1> 要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱
e.g
/**
* Created by Chal Nan on 6/30/14.
*/
public class Test {
public static void main(String[] args) {
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
}
}
这段代码中会无意识中创建大量多余的Long实例,将sum的声明从Long改成long会是性能得到提升。
6> 消除过期的对象引用
长生命周期的对象持有短生命周期的对象引用会造成内存泄露。
1> 内存自己管理的数据对象,一旦数组元素变成了非活动部分的一分部,程序员需要手动的置空这些数据元素
2> 缓存 -> WeakHashMap: 当除了自身有对key的引用外,此key没有被其他引用持有,那么map会自动丢弃这个 Map.Entry
3> 监听器和其他回调
7> 避免使用终结(finalize)方法
1> finalize方法通常情况下是不可预测的,也是很危险的,一般情况下避免使用该方法。
2> 一般情况下,finalize方法的执行时间不确定,也不能保证该方法一定会被执行,因此不能当做析构方法来使用
3> 使用finalize方法有一个非常严重的性能损失
4> 除非是作为安全网,或者是为了终止非关键的本地资源,否则请不要使用终结方法。
5> 若使用了终结方法,就要记得调用super.finalize。
8> 覆盖equals时请遵守通用约定
equals方法需要实现等价关系:
1> 自反性, x.equals(x) == true (x != null)
2> 对称性, x.equals(y) == true, y.equals(x) == true
3> 传递性, x.equals(y) == true, y.
equals(z) == true, x.equals(z) == true
4> 一致性, 只要对象信息没有被修改,多次调用 x.equals(y)就会一致地返回true,或者false。
x.equals(null) == false
9> 覆盖equals时总要覆盖hashCode方法
1> 在每个覆盖了
equals方法的类中,也必须覆盖hashCode方法
2> 两个相等的对象(x.equals(y) == true),这个两个对象的hashCode必须要相等。(x.hashCode() == y.hashCode())
3> 两个hashCode相等的对象,不一定是相等的两个对象。但不同的对象能产生不同的hashCode,有可能提高hash table的性能
10> 始终覆盖toString方法
11> 谨慎地覆盖clone
1> 浅拷贝和深拷贝: http://blog.csdn.net/bluescorpio/article/details/4322682
2> 实现对象拷贝的好方法是提供一个拷贝构造器或者拷贝工厂。
12> 考虑实现Comparable接口
1> 考虑equals方法的实现原则。
2> compareTo() 方法的返回类型是int,需要确保该方法的返回值不会溢出。(Integer.MIN_VALUE)
13> 使类和成员的可访问性最小化
1> 类具有公有的静态final数据域,或者返回这种域的访问方法,这几乎总是错误的。因为客户端可以修改数组中的内容。
e.g 使用Collections.unmodifiableList()方法把不可变数组变成不可变列表。
14> 在公有类中使用访问方法而非公有域
1> 公有类不应该直接暴露数据域,而是提供getter/setter方法。
正确的例子:
public class Test {
private int arg1;
private String arg2;
public int getArg1() {
return arg1;
}
public void setArg1(int arg1) {
this.arg1 = arg1;
}
public String getArg2() {
return arg2;
}
public void setArg2(String arg2) {
this.arg2 = arg2;
}
}