第2章 创建和销毁对象

何时以及如何创建对象,何时以及如何避免创建对象
如何确保适时销毁,如何管理对象销毁前必要的清理

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

静态工厂方法是一个返回类的实例的静态方法,对它其实只是一个普通的静态方法而已,需要注意的是它与设计模式中的工厂方法不同,不要弄混淆了

Java源码中的例子:

 public static Boolean valueOf(boolean b){
    return b?Boolean.TRUE:Boolean.FALSE;
 }

优势

列举静态工厂方法与构造器相比,有哪些优势

静态工厂方法有名称

构造方法没有名称,给静态工厂取一个适当的方法名称会更易于阅读,也更易于客户端使用.

特别是在面对有多个参数或者多个构造方法的类的时候,会让客户端不知道如何选择构造方法(自行脑补一个大写的懵B).

不必在每次调用它们的时候都创建一个新对象

我们知道构造方法每次都会创建一个新的实例,而当我们需要避免重复创建不必要的对象(或者不可变的类)时通过构造方法去做是做不到的,而静态方法可以为重复的调用返回相同的对象(比如返回的对象需要是一个单例)

它们可以返回原返回类型的任何子类型的对象

构造方法只能返回类本身,而静态方法可以返回它的子类,利用多态的特性使得静态方法更加灵活
比如Executors类的各种newxxx方法返回ExecutorService的子类

在创建参数化类型实例的时候,它们使代码变得更加简洁

调用参数化构造器时,即使类型参数很明显也必须指明.
书中列举了实例化HashMap的例子:

Map<String,List<String>>m = new HashMap<Stirng,List<String>>();

如果用静态工厂可以这么写:

public static <K,V>HashMap<K,V>newInstance(){
    reutrn new HashMap<K,V>();
}

想想以前也确实烦这些类型指定,一写一长串,但是现在的JVMS(Java1.7)已经实现了类型推导,所以其实也没那么复杂了.

劣势

静态工厂方法的劣势

类如果不含公有的或者受保护的构造器,就不能被子类化

它们与其他的静态方法实际上没有任何区别

确实,静态方法真的只是一个静态的方法而已,如果文档上不提到创建该类的实例可以使用静态方法的时候,很容易被忽略

所以能我们需要遵守一定的命名习惯:

静态方法推荐的命名名称
  • valueOf 返回的实例与参数具有相同的值,一般用于类型转换(如String Boolean Double等等)
  • of valueOf的简洁代替
  • getInstance 返回的实例工具参数而定,对于单例,则一般没有参数,并且每次返回的都是同一个实例
  • newInstance 每次返回一个新的实例
  • getType
  • newType

不能很好的扩展到大量的可选参数

当参数非常多的时候静态方法的可读性,维护性等就非常差了,这个后面会说

实际运用

现在在我们新建一个Fragment的时候,AS会自动生成一个newInstance(String ,String )的一个方法,这个就是静态工厂方法了,可见官方也推荐我们使用静态工厂方法.

另外Java源码中也有非常多的静态工厂方法的运用,比如上面提及的Executors,自己去体会~

小结

静态工厂方法与构造器各有优势,不过一般来说静态工厂通常更加合适,所以以后多考虑使用静态工厂吧.

第2条 遇到多个构造器参数时要考虑用构建器(Builder)

当实例化一个类时有很多可选参数的时候,我们或许会写很多不同参数的构造方法,可读性会非常差,并且客户端也不知道在什么时候用什么构造器,这是非常非常糟糕的,同样静态方工厂也不能避免,这个时候我们需要用到构建器,也即设计模式里的Builder模式

Builder模式非常常见了,列举个列子就过了:

        AlertDialog dialog = new AlertDialog.Builder(this)
                .setCancelable(true)
                //...各种可选参数 想要什么设置什么
                .setMessage("Builder模式")
                .create();

Builder模式虽然能解决多参数遇到的问题,但是它也有缺点:
为了创建对象,我们必须先创建一个Builder,这是一个多余的开销,虽然开销并不明显,但确实存在.

小结

当有多个参数的时候,Builder模式是非常不错的选择.

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

所谓Singleton即单例,指仅仅被实例化一次的类,这一条与单例息息相关.

私有构造器强化

写过单例的一定知道,构造器一定要私有,否则别人随便new,怎么保证单例呢?

书中还讲到了单例如何防反射,防反序列化,这里就不提了

枚举强化

java 1.5 版本之后,单例多了一个实现方法(包含单个元素的枚举类型):

public enum Elvis{
    INSTANCE;
    public void leaveTheBuilding(){...}
}

优势:

  • 无偿提供序列化机制
  • 绝对防止多次实例化
  • 防反射
  • 简洁

书中说:单元素的枚举类型已经成为实现Singleton的最佳方法,可惜的是我没在实际中用过,也没见过这种实现方式.

小结

单例有很多实现方式,也是不容易的~

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

首先理解什么是不可实例化?
不可实例化是指只包含静态方法和静态域的类
比如BitmapUtil等各种Utils,它们包含各种静态方法,但是实际上我们不会也不需要去实例化它!

静态域(static-field) 比如:public static Object obj

既然工具类不希望被实例化,那么如何做呢?

提供一个私有构造器,并在里面抛出异常即可

eg:

public class Util{
  private Util{
   // Suppress default constructor for noninstantiability
   throw new AssertionError();
  }
}

相信都会感觉这多此一举,谁tm没事去实例化工具类啊,以前我也这么觉得,直到我的膝盖中了...

偶不,直到我在优秀的库中看到这写法,比如RxJava中的Subscriptions类:

public final class Subscriptions {
    private Subscriptions() {
        throw new IllegalStateException("No instances!");
    }
    //...
}

又如Jake大神的RxBinding中各种RxXXXX也是如此:

private RxAppBarLayout() {
    throw new AssertionError("No instances.");
  }

优秀的项目,细节处理都非常优秀

小结

有时候有些东西非常有道理,只是自己太弱小,悟不到而已,虚心学习,keep growing

PS: EffectiveJava是本好书,RxJava是个优秀的库,Jake是真大神!!

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

一般的讲,最后能重用对象而不是在每次需要的时候创建一个相同功能的新对象.
另外对于一个不可变的对象(immutable 后面会讲),它始终可以被重用.

作者举了几个例子来说明:

创建String实例

String s = "stringette";替代String s = new String("stringette")
因为后者的参数其实就是一个实例,每一次调用都会多创建一个没用的对象.

Boolean

    public static final Boolean TRUE = new Boolean(true);
    public static final Boolean FALSE = new Boolean(false);

Boolean.valueOf()方法重用了FALSETRUE来避免重复创建相同功能的对象

自动装箱autoboxing

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

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

eg:

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倍多,非常可怕啊

so,记住,优先使用基本类型!

PS 这里要说的不是创建对象非常昂贵,因为小对象的创建和回收是非常廉价的

对象池(object pool)

维护对象池来避免创建对象只针对非常重量级的对象,如数据库连接池

Android中对象池有很多,如Message类,又如Glide中的Bitmap池

对象池的缺点

  1. 代码更乱 涉及到回收、重用必然会增加许多代码
  2. 增加内存占用,损害性能

小结

当需要重用的时候,就不要创建

第6条 消除过期的对象引用

首先需要明确,Java即使有GC,我们依然要自己考虑内存管理的事情.

当一个数组扩容后又缩减,比如size从0->200->100(一个栈先增长,后收缩),那么元素的index>=100的那些元素(被pop掉的)都算是过期元素,那些引用就是过期引用(永远不会再被解除的引用)

过期引用导致了内存泄露

虽然对于自己来说pop掉的元素我们不会去用,但是由于过期引用的存在,GC并不会去回收它们,所以需要我们手动清空这些引用.

eg:

public Object pop(){
    if(size==0) throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null; //Eliminate obsolete reference
    return result;
}

PS:书中还提到了 磁盘交换(Disk Paging)-->wiki
备注:虚拟内存

第7条 避免使用终结方法

终结方法:finalizer (老实说,这个真没用过)

没看懂,记录一些点..

  • 终结方法会导致行为不稳定,降低性能,以及可移植性问题
  • 不能保证会被及时地执行,而且根本不保证它们会被执行(这..好过分..)

还是没看懂,被自己蠢哭了..

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

推荐阅读更多精彩内容