EffectiveJava笔记 第一章

来源:互联网 发布:工作计划制定软件 编辑:程序博客网 时间:2024/06/05 03:53
                    EffectiveJava笔记第一章:创建和销毁对象1:用静态工厂方法代替构造器    优点:    i:静态工厂方法有名称,而构造方法只有一个名称函数名        a:可读性强,而且不受构造器方法签名的限制    ii:静态工厂方法不必在每次调用他的时候都创建一个对象        a:静态工厂方法可以缓存对象,而构造器每次都会创建一个对象(可以说静态对象的方法是实力受控的)    ii:静态工厂可以返回原返回类型的任何子类型        a:这样了易理解为面向对象语言的多态的好处,可以参考工厂方法。    iv:静态工厂方法可以使代码变得更简洁        其实这里的例子主要是说创建集合的时候,实例化时可以进行泛型的推倒。    缺点:    i:如果类不含有共有的或者被保护的构造器就不能被子类化        这一点是什么意思呢,我自己感觉是,在实例化子类的时候,子类的构造器的第一句都是super(),如果父类没有对应的实例化方法,你可以猜想到在你编译的时候会发生情况(这个你可以自己动手实验)    ii:静态工厂方法本质伤害是一个静态的方法(其实在我的理解里边我近似的把构造方法看成了静态方法),        这样打来的不变主要还是在javaapi文档里边。    在这里书上也总结了一下:        valueOf: 不是太严谨的将,这种方法其实就是类型的转换,比如:BOOLEAN,INTEGER等方法        of: 应该是一种valueOf的一种变体,观察一下EnumSet可能你会就马上明白了        getInstance:返回的实例是通过方法的参数来描述的,但是不一定与你传递的参数有相同的值,单利模式可能用的比较多,单例模式的误区我想大家应该都知道,一般也就是线程安全,以及你所传递的参数的引用是否想变成整个生命周期的        newInstance:类似getInstance,但是区别也比较明显,就是返回的每个实例可能都与所有的其他实例不同        getType:类似于getInstance,但是在工厂方法处于不同的类中的时候使用,Type返回的对象的类型        newType:类似于newInstance,但是在工厂方法处于不同的类中的时候使用,Type返回的对象的类型2.构造器的参数比较多的时候需要考虑构建器    前言:不知道我这么理解对不对,参数比较多的时候,使用构建器模式,可以去掉相对多的构造函数,但是构造器实例化之前可能还需要你创建一个Builder,对于注重性能的时候可能这个并不是你想要的,但是构造器在多个可选参数(一般多余三个的时候)是很方便的。构造器以及JavaBean的缺点:重叠构造器来实现其实是可行的,但是你想一个类有四个可选参数需要你写多少个构造器来完成?JavaBean的缺点就是set/get方法都是共有的,如果你想保护一个对象不被改变,是不是还需要在许多其他的方面考虑,比如线程安全,当然适用对象的冻结也可以,但是前提是这样维护你能确定在任何的情况下都不出错,并且付出的努力不会更多?Builder模式:其实builder模式却可以更优雅的做到上边两种情况做不到的。其实我感觉builder的模式应该是个程序员就可以写出这种模式来,我就不详细的说了,我写的是读书中对我的影响比较大的地方,所以如果大家有什么问题可以看原版书,如果在网上找不到可以找我要这本书的pdf,注意:a:最重要的其实也就是参数验证,有两种情况,一种是在对象域一种是在builder中进行参数验证,前者是在builde方法中抛出IllegalStateException.后者是在builder的set/get方法中抛出,这样在build之前就可以验证错我,所以我自己用的时候一般都是倾向于后者。      b:builder对象其实比较灵活,一个builder可以创建一个对象或者多个对象,一般builder.build()方法创建的对象多是不可变的。3.私有构造器或者枚举类型来强化单例模式jdk1.5之前实现单例模式的两种方法:    a:私有的构造器+共有的final域    b:私有的final静态变量域+私有的构造器+公有的静态方法(例:getInstance)为了使单例模式的程又可以序列化,指甲上实现的接口以及UUId是不可以的,还需要保证实例域是瞬时的,并提供一个readResolve方法,否则每次发序列化就会创建一个该对象。所以现在又有了一个先的方法创建单利模式,而且还没有上述的烦恼,那就是使用枚举类型(包含单个元素的枚举类型)

4:通过私有的构造器强化类不可实例化的效果
在开发中可能都碰见过专门写的一些工具类,有的时候有些人可能无意识的将这些类实例化了。应该都知道编写类的时候,你没有声明构造器,系统会有一个默认的没有参数的共有构造器,所以为了避免上面的这种情况,应该保持给工具类提供私有的构造器类避免。
5:避免创建不必要的对象
i:有这么一条原则:如果对象是不可变的,那么他就始终可以被重用。
举个简单的例子吧:String s=new String(“abc”); 这个语句在创建字符串的时候创建了两个对象,所以大家现在知道为什么你跟着别人学的时候String s=“abc”;的原因了吧虽然简单但是确实需要注意的尤其是在一些循环语句中
ii:对于同时提供了静态工厂方法和构造器不可变的类,通常使用静态工厂方法来便面重复创建对象
iii:对于已知的不可变的类,可以通过改变他的作用域来减少创建对象的次数,比如Date对象创建出来就会不可变了。当然详细的例子你可以看这本书,我只是作总结,方便自己和别人回顾。
iv:构建多余对象的典型的例子就是装箱基本数据类型与基本类型混合使用,这样的话你可以猜想在一个循环中不断的创建装箱对象队形能的影响。
注意:上述几条注意点并不是告诉你要尽量少的创建对象,而只是一种思路,而且创建附加的小对象,因为回收和创建比较简单,可以是程序更加清晰简洁更具功能性。(不知道为什么这句话让我想到了组合)
而且不建议使用自己的对象池来维护,通常你会付出许多代价,而且你并不一定比自带的jvm做的更好。
6.消除过期的对象引用
a:消除过期的对象引用,怎么说呢,我感觉本质上就是长周期对象持有短周期对象的引用,所以当累自己管理内存的时候还是需要注意什么时候需要清除对对象的应用,时刻保持警惕。
b:还有就是缓存中的对象也很容易被遗忘,WeakHashMap可能对你的帮助比较大,只有键在外边又被引用的时候才不会被回收。
c:内存泄漏的第三个常见的来源就是监听器以及回调(这种情况使用若引用可能会更加的方便一些吧)
7.避免使用终结方法
前段时间看了一短时间的c++的基础,我发现从java调到C++确实没有C++调到Java简单,因为Java是不需要维护指针的,我看c++的时候发现析构函数和中介方法特别相像,可是看了一段时间之后发现并不是这么一回事,那是什么情况呢,正好effectiveJava这本书里边说了,然后点一下比较重要的点吧。(类似c++的析构函数的工作一般是在try-finally块里执行的)
i:分析终结方法:
a:终结方法并不保证会及时执行,有事可能很长一段时间之后执行,也可能永远也不执行,所以注重时间的任务不要放到终结方法里边。例:例如使用终结方法光比已经打开的文件,这个光想想就很可怕
b:而且终结方法的及时执行和JVM的依赖还比较大,可能不同的JVM可能执行的时机不同,所以你还敢保证你的java代码是跨平台的么。
c:不要被system.gc和System.runFinalization这两个方法迷惑,他们确实增加了终结方法执行的机会,但是一定会执行终结方法
d:在终结过程中抛出异常,那么不仅仅会破坏对象,而且连异常也不会被抛出,能想象的到这个在调试的时候是多么的尴尬。
e:使用终结方法销毁对象,会给性能产生巨大的负担
ii:终结方法的替代
有些情况使用终结方法是可以被替代的,就是用显式终止方法来代替他,就比如InputStream和OutputStream以及java.sqlConnection上的close方法。还有就是Timer的Cancel方法。
显式的终止方法是和try-finally结构结合使用的以确保及时终止,例如关闭流的情况大部分是在finally里边执行的。(对了在finally中使用return的严重后果我在这就不赘述了,我强烈建议去网上搜搜,会让你更深刻的认识try-catch)
iii:终结方法的作用:
a:当显式的终止方法没有被调用的时候,终结方法就相当于最后一层安全网,
b:本地对等体的使用,使用过jni开发的人都知道,有的时候java曾和Native可能有相通概念的对象,但是虚拟机能够检测到java对象,但是jni对象怎么办呢,这个时候终结方法就有作用了,稍一思考你就会明白了
iv:使用终结方法需要注意的情况
a:子类的终结方法被覆盖之后需要手动的调用父类的终结方法,并且父类的终结方法必须在自雷终结方法之后,这个和构造函数第一句调用父类的构造器的原理有异曲同工的道理。
b:如果没有在子类的终结方法中调用父类的终结方法,那么父类的终结方法永远不会被调用到,(引申的终结收尾者的例子也可以自己去搜一下,其实还是很有意思的)

0 0
原创粉丝点击