《Effective Java》第一章——创建和销毁对象

内容摘引自《Effective Java》(第二版,机械工业出版社)

第一条:考虑用静态工厂方法代替构造器

这样做的好处

  • 静态工厂方法有名称,能够让人更易阅读,防止在开发过程中忘记应该使用哪个构造器的情况
  • 不必每次调用的时候都创建一个新的对象,当需要不可变类(实例内容不可改变的类)的时候可以使用预先构建好的实例,从而避免了重复创建对象,提升了性能
  • 它可以返回原返回类型的任何子类型对象,从而提高的灵活性
  • 在创建参数化类型实例的时候,它能使得代码变得简洁

静态工厂方法的缺点

  • 类如果不含有公有的或者受保护的构造器,就不能被子类化
  • 它与其他的静态方法实际上并没有任何区别,他可能不能像API文档那样直接明确标识出来

静态方法的惯用名称

  • valueOf——类型转换,返回与它参数相同的值
  • of——是valueOf的简洁替代
  • getInstance——返回的实例时通过方法的参数来描述的,但不能够说与参数有相同的值。对于Singleton(单例)来说,改方法没有参数,并返回唯一的实例
  • newInstance——类似于getInstance,但是newInstance能够确保返回的每一个实例都与其他的不同
  • getType——像getInstance一样,表示工厂方法返回的数据类型,主要早不同的类的时候使用。
  • newType——像newInstance一样,但是在工厂方法处于不同的类中的时候使用。Type表示工厂方法返回的对象类型

服务提供者框架

定于:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来。
这是一个静态工厂方法的实例
服务提供者框架包含四个部分

  • 服务接口(Service Interface),这是提供者实现的
  • 提供者注册API(Provider Registation API),这是系统用来注册实现的,让客户端访问他们的。
  • 服务访问API(Service Access API),是客户端用来获取服务的实例的。它一般允许但是不要求客户端指定某种选择提供者的条件,如果客户端没有这样的指定,那么一般会返回给一个默认的实例。它是一个“灵活的静态工厂”,它构成了服务提供者框架的基础
  • 服务提供者接口(Service Provider Interface),这是一个可选的,这些提供者负责创建其服务实现的实例。如果没有提供实例那么实现就按照类名进行注册,并通过反射方式进行实例化。

第二条:遇到多个构造器参数是要考虑用构建器

当一个实体有多个属性,而有的属性是非必需的那么在创建实例的时候可能会有多个构造函数可供选择,举例来说如下

package com.myclass;

public class OldPerson {
    private int age;
    private String name;
    private double weight;
    private String hobby;
    public OldPerson(int age, String name, double weight, String hobby) {
        // TODO Auto-generated constructor stub
        this.age = age;
        this.name = name;
        this.weight = weight;
        this.hobby = hobby;
    }
    
    //当weight和hobby不是必须的时候,我们在创建OldPerson就需要这样
    public OldPerson(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

如果有很多个参数那么构造函数就可能会有很多,可能会在使用的时候不小心颠倒了两个参数或者别的小问题,所以这种重叠构造器模式是可以的,但是当有许多参数的时候,客户端代码会很难编写,并且难以阅读。

更好地方法

package com.myclass;

public class Person {
    private int age;
    private String name;
    private double weight;
    private String hobby;
    
    public static class Builder {
        //必填参数
        private String name;
        
        //选填参数,设置默认值
        private int age = 0;
        private double weight = 0.0;
        private String hobby = "写bug";
        
        //设置必填参数
        public Builder (String name) {
            this.name = name;
        }
        
        //设置非必填参数
        public Builder age(int age) {
            this.age = age;
            return this;
        }
        public Builder weight(int weight) {
            this.weight = weight;
            return this;
        }
        public Builder hobby(String hobby) {
            this.hobby = hobby;
            return this;
        }
        
        public Person build() {
            return new Person(this);
        }
    }
    
    public Person(Builder builder) {
        // TODO Auto-generated constructor stub
        age = builder.age;
        name = builder.name;
        weight = builder.weight;
        hobby = builder.hobby;
    }
}

这样当我们使用的时候只需要这样

     Person person = new Person.Builder("Slience爱学习").weight(120).hobby("看书").build();

就可以了(虽然我用的比较多的是JavaBean模式)

第三条:用私有构造器或者枚举类型强化Singleton属性

(这一条没怎看懂)

第四条:通过私有构造器强化不可实例化的能力

我们知道当类中没有显式的构造器的时候,系统会自动生成一个缺省的构造器,当我们想要让一个类不能被实例的时候(比如说一些工具类),我们可以自己写一个构造函数,并把构造函数设置为私有的,这样就不会创建这个实例了,举例来说就是

package com.myclass;

public class MyClass {
    public static String say() {
        return "Hello World";
    }
    private MyClass() {
        // TODO Auto-generated constructor stub
    }
}

这样我们就创建不了MyClass实例,而只能使用它的say方法了。

第五条:避免创建不必要的对象

String str = "Hello World";
String str2 = new String("Hello World");

str相对于str2效率要高,因为在创建对象的时候"Hello World"已经是一个对象了,没有必要在用一层new String包裹起来再创建一个对象。
再举一个例子

        long start = System.currentTimeMillis();
        long sum = 0L;
        for(long i = 0; i < Integer.MAX_VALUE; i++) {
            sum += i;
        }
        System.out.println(sum);
        System.out.println("耗时:" + (System.currentTimeMillis() - start));

        long start = System.currentTimeMillis();
        Long sum = 0L;
        for(long i = 0; i < Integer.MAX_VALUE; i++) {
            sum += i;
        }
        System.out.println(sum);
        System.out.println("耗时:" + (System.currentTimeMillis() - start));

两者的执行耗时是不一样的,后者使用Long的耗时更大,因为要将i转成Long给sum加上,这意味着程序创造了不必要的很多个Long实例,造成了更多的耗时。

第六条:消除过期的对象引用

(原书是一个栈增长再减少的例子),减少掉的元素可能不会被垃圾回收,在极端情况下可能会造成内存泄漏。这是因为栈内部维护者这些对象的过期应用。
过期应用是指永远也不会被解除的引用。
解决这种问题的办法也很简单,那就是当对象引用过期的时候清空这些引用就可以了。

        String[] strs = {"星期一","星期二","星期三","星期四"};
        //如果要取出最后一个,应该这样
        String str = strs[strs.length-1];
        strs[strs.length-1] = null;
        System.out.println(str);

这样做的好处是当你不小心错误的解除引用,程序会报空指针异常而不是悄咪咪的运行下去。

第七条:避免使用终结方法

终结方法finalizer的线程优先级比其他应用程序的线程要低,如果要使用finalizer去结束一个一个比较有限的资源,比如说打开很多个文件的描述符(原文如此,可能是指explorer这样的东东吧),当你想要关掉它的时候再打开新的,因为优先级低所以可能先去打开新的然后旧的没有去关掉,关掉的速度比打开的速度低造成了资源的占用。比较常见的终结方法有InputStream、java.sql.Connention中的colse方法。
显示终结方法通常与try-finally结合起来使用,确保及时终止。
终结方法前使用try-finally显示终结的好处

  • 可以充当终结方法的“安全网”,这样就算终结方法没有按时关闭也可以有所动作以便做一些补救。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容