创建和销毁对象
1.考虑用静态工厂方法代替构造器
- 静态工厂方法有名称
String.valueOf("1")
静态工厂方法不必在每次调用它们的时候都创建一个新的对象
创建对象不适用 new 关键字静态工厂方法可以返回原返回类型的任何子类型
其实就是静态工厂方法返回值可以是多态,new 出来的必须返回原对象在创建参数化类型实例的时候,代码变的简单
原来是:
Map<String, List<String>> m = new HashMap<String,List<String>>();
如果使用静态工厂方法:
Public static <K,V> HashMap<K,V> newInstance(){
return new HashMap<K,V>();
}
创建对象的时候可以这样:
Map<String, List<String>> m = HashMap.newInstance();
2.遇到多个构造器参数时要考虑用构造器
如果需要很多的构造器,那样代码会变得非常繁琐并且不实用,每次 new 一个对象时还必须查看构造器的参数。
- 使用 JavaBean 的setter 和 getter 方法解决
缺点一:在构造过程中JavaBean可能处于不一致的状态
缺点二:JavaBean模式阻止了把类做成不可变的可能,多线程的情况下会出现问题 - Builder模式
Builder模式我们很常用,推举使用
3.用私有构造器或者枚举类型强化Singleton属性
其实就是单例模式
4.通过私有构造器强化不可实例化的能力
就是工具类加一个私有的构造,再抛出一个异常
public class Util{
private Util(){
throw new Error();
}
}
5.避免创建不必要的对象
5.1 反例一
用
String s = new String("hello");
代替
String s = "hello";
虽然看起来没太多区别,但是如果在for循环里面或者方法的多次调用里面,每次new一个对象会被性能造成很大的影响。
5.2反例二
有如下代码:
public class Person{
private final Date birthDate;
//省略一些初始化
//这是错误的写法
public boolean isBabyBoomer(){
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
Date boomStart = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
Date boomEnd = gmtCal.gettTime();
return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0;
}
}
其实这段代码看着没什么问题,并且我们日常中也是这么写的,但是它在性能上是有很大的缺陷的。
Date对象一旦计算出来之后就不会再变化了。
isBabyBoomer()方法每次调用时,会新建一个Calender、一个TimeZone和两个Date实例,这是不必要也是浪费性能。
推举使用下面的静态static代码块初始化:
class Person{
private final Date birthDate;
private static final Date BOOM_START;
private static final Date BOOM_END;
static{
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = gmtCal.gettTime();
}
public boolean isBabyBoomer(){
return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0;
}
}
static修饰的代码块会在类初始化进行加载,并且只会加载一次,所以Calendar、TimeZone和Date也只会实例化一次,而不是每次调用方法的时候都进行开辟内存进行实例化。
如果isBabyBoomer()没用到,其实没必要加载static代码块,使用延迟初始化。虽然性能会好很多,但是导致太复杂了,反而有点过于为了性能而优化了。
5.3不要莫名的自动拆装箱
6.消除过期的对象引用
- 只要类是自己管理内存,程序员就应该警惕内存泄漏问题
- 内存泄漏的另一个常见来源是缓存
- 内存泄漏的第三个常见来源是监听器和其他回调,确保回调立即当作垃圾回收的最佳方法是使用弱引用
7.不要使用终结方法
尽量不要使用 System.gc 和 System.runFinalization 这种终结方法,他们确实增加了终结方法被执行的机会,但是他们并不保证终极方法一定会被执行。
终结方法有一个很严重的性能损失。
但是显示的终结方法除外,try...finally...