《Effective Java》笔记06:避免创建不必要的对象

  1. 重用不可变的对象
  2. 重用已知不会被修改的对象
  3. 自动装箱 autoboxing

一般来说,最好能重用对象而不是在每次需要的时候就创建一个相同功能的新对象。重用方式即快速,又流行。如果对象是不可变的,它就始终可以被重用

重用不可变的对象

String s = new String("stringette"); // 不要这样做,会创建新的 String 实例
String s = "stringette"; // 对于所有在同一台虚拟机中运行的代码,只要它们包含相同的字符串字面常量,该对象就会被重用。在常量池中。

对于同时提供了静态工厂方法和构造器的类,通常使用静态工厂方法,以避免创建不必要的对象。如,静态工厂方法 Boolean.valueOf(String),总是优先于构造器 Boolean(String)后者在 Java 9 中被弃用。构造器每次被调用都会创建一个新对象,而静态工厂方法不要求这样做。

重用已知不会被修改的对象

假设我们需要:检验一个人是否是出生在 1946-1964 年之间

public class Person{
    private final Date birthDate;
    //Dont do this
    public boolean isBabyBoomer(){
        // Unecessary allocationof expensive object
        Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"))
        gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);
        Data boomStart = gmtCal.getTime();
        gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"))
        gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);
        Data boomEnd = gmtCal.getTime();
        return birthDate.compareTo(boomStart) >= 0 &&
            bitrthDate.compareTo(boomEnd) < 0;
    }
}

在以上这个实例中,我们发现,每次每次方法的调用 都会创建 一个 Calendar 、一个 TimeZone、和两个 Date 实例,而且我们只是需要比较 Date而已,并且这个 Date 的值其实是不变,我们可以用一个静态的初始化器,避免这种效率低下的实现方式。

public class Person{
    private final Date birthDate;

    private static final Date BOOMT_START;
    private static final Date BOOMT_END;
    static {  // 我们在静态方法块中初始化这些字段
        Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"))
        gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);
        BOOMT_START = gmtCal.getTime();
        gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"))
        gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);
        BOOMT_END = gmtCal.getTime();
    }

    public boolean isBabyBoomer(){
        return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) <0;
}

自动装箱 autoboxing

自动装箱允许我们将基本类型和装箱基本类型(Boxed Primitive Type)混用,按需自动装箱和拆箱

它们俩之间性能是有明显的差别的(基本类型更优)

public static void main(String[] args) {
    Long sum = 0L;
    for(long i=0; i<Integer.MAX_VALUE; i++) {
        sum += i;
    }
    System.out.println(sum);
}

sum 的类型为 Long,这样会比 long 多创建约 2 的 31 次方的 Long 实例,影响性能,所需时间大约是 long 的 6 倍多

优先使用基本类型!

这里要说的不是创建对象非常昂贵,因为小对象的创建和回收是非常廉价的,特别是在现代的jvm实现更是如此。通过创建附加的对象,提升程序的清晰性,简洁行和功能性,这通常是件好事。

类初始化的顺序: 先初始化父类的静态代码 —> 初始化子类的静态代码 —> 初始化父类的非静态代码 —> 初始化父类构造函数
—> 初始化子类非静态代码 —>初始化子类构造函数。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com

文章标题:《Effective Java》笔记06:避免创建不必要的对象

文章字数:809

本文作者:Bin

发布时间:2016-05-11, 14:25:57

最后更新:2019-08-06, 00:42:44

原始链接:http://coolview.github.io/2016/05/11/Effective-Java/%E3%80%8AEffective%20Java%E3%80%8B%E7%AC%94%E8%AE%B006%EF%BC%9A%E9%81%BF%E5%85%8D%E5%88%9B%E5%BB%BA%E4%B8%8D%E5%BF%85%E8%A6%81%E7%9A%84%E5%AF%B9%E8%B1%A1/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录