读书笔记

《Effective Java》第二章:创建和销毁对象

2018-03-08  本文已影响24人  ldlywt

创建和销毁对象

1.考虑用静态工厂方法代替构造器

String.valueOf("1")
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 一个对象时还必须查看构造器的参数。

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...

上一篇下一篇

猜你喜欢

热点阅读