《EffectiveJava》读书笔记
《Effective Java》读书笔记⽬录,这篇⽂章记录了我读这本书的⼀些想法和验证。
1. 考虑⽤静态⼯⼚⽅法代替构造器
第⼀条,考虑⽤静态⼯⼚⽅法代替构造器
优点⼀:静态⼯⼚可以很好的理解名称
四个构造⽅法,⾯对这样的构造⽅法,三个、四个是可以接受的,那如果是七个⼋个甚⾄是⼗⼏个呢?这个时候有⼀个好的名字就是⼗分重要,⽐如书上提到的返回素数的⽅法名称:BigInteger.probablePrime(),这样的名称就可以很好地区分构建实例的⽤途,可读性也更强。
优点⼆:不必每次调⽤它们的时候都创建⼀个新的对象
类StaticFactoryDemo在初始化的时候会缓存10个对象到ArrayList中,可以实习对象的复⽤,这⾥只说⼤概意思,具体对象池、对象⼯⼚实现可以参考Integer、Spring的IOC。
炸土豆块的做法优点三:它们可以返回原返回类型的任何⼦类型的对象
聪明的猫头鹰
为了⽅便阅读,不添加多余实现,在StaticFactoryDemo中创建的newInstance()⽅法⽤于创建实例,这个⽅法的实现中返回了⼦类的实例,使我们的代码更灵活。
优点四:在创建参数化类型实例的时候,他们使代码变得更加简洁。(已被优化)
作者的观点是过多参数会使代码看起来不是很简洁,如下代码。
国子作者提供的解决办法是在HashMap中提供newIntance()⽅法,⽅法中返回复杂的泛型实例。
我的jdk版本为1.8,现在已经采取参数推断,做了优化,如下
静态⼯⼚⽅法也是有缺点的
缺点⼀:类中如果不含有public或者protected修饰的构造⽅法,是⽆法拥有⼦类的。
缺点⼆:如果没有⼀个漂亮的名字和注释,其他⼈是很难分清这个⽅法是不是⽤来构建实例的,静态⼯⼚⽅法和普通静态⽅法实际上没有任何区别。
作者提供了⼀些名字供参考,valueOf、of、getInstance、newInstance、getType、newType。
总结:静态⼯⼚⽅法可以提供给我们漂亮的可供区分的名字,可以提供缓存使对象复⽤,可以灵活的返回⼦类实例。同时要注意,如果没有提供公有或者受保护的构造⽅法时,是⽆法被继承的,起⼀个漂亮的易于理解的名称同样也很重要,注意要与设计模式中的⼯⼚⽅法区分开。在需要创建对象时,要先考虑静态⼯⼚⽅法,不要直接就选公有的构造⽅法。
2. 遇到多个构造器参数时要考虑⽤构造器
如果⼀个对象有多个参数时,应该如何处理?
代码⼤全2中提到过,⼀个函数的参数最好不要超过7个,我们熟悉的线程池参数就是7个,构造⽅法也不例外,在笔记本电脑中,⼀屏幕代码最多也就是7个左右的参数。
四川卧龙
可爱女孩子头像构建⼀个对象,通常我们会如何处理呢?
1、构造函数,下⾯的类BuilderDemo有8个属性
金泉社区
这样的代码是⼗分冗长的,如果有多个构造函数的话,是⼗分混乱的。
于是我们有个新的想法,创建这些属性的getter/tter⽅法
2、JavaBeans模式
这样的做法因为将设置属性分为了很多步,可能会出现线程安全问题,导致程序出现对象不⼀致的情况,需要开发⼈员⾃⼰去把控。
3、Builder模式
可耻的照扒了书中的代码如下:
过程就是创建⼀个静态内部类,成员变量通过final修饰保证线程安全,通过返回this,像链式⼀样调⽤。
总结:显然在参数过多的情况下,通过构造函数来构建对象的⽅式是不可取的,effective java作者推荐了Builder模式,从上⾯我们可以看出,其实增加了很多代码量(问号脸)JavaBeans的⽅式是可以通过编译器⼀键⽣成的,个⼈认为:从⼯作效率的⾓度看,JavaBeans的⽅式⽤的更多,⽽Builder的⽅式看起来更优雅。
3. ⽤私有构造器或者枚举类型强化SingleTon属性
我们⽿熟能详的单例有懒汉式、饿汉式等
例如下⾯这段的饿汉式
水之缠绵
⽤private修饰构造⽅法,防⽌外界通过⽆参的构造⽅法直接创建对象,但是这样还是可以通过反射来
攻击,造成代码的不安全,可以考虑设定⼀个变量,在创建第⼆个对象的时候抛出⼀个⾃定义的异常。
这样就安全了吗?
如果我将这个对象序列化到本地,然后再反序列化回来,这个对象还是原来的对象吗?不是的,这时可以考虑使⽤序列化的hock函数readResolve()来解决,当反序列化时,就会⾃动调⽤这个 readResolve⽅法来返回我们指定好的对象,如下图
还有⼀种⾮常简洁的⽅式,通过枚举实现单例
皂角的作用与功效是什么Single就是要实现单例的类,通过Instance()创建单例对象,枚举实际上是⼀种语法糖,反编译后会发现是由静态⽅法和匿名内部类组成。
总结:单例的实现有很多种,还有double-check,同步⽅法等⽅式实现,在这⾥不⼀⼀赘述,在effective java中作者强烈推荐枚举来实现⾼效安全的单例,不会被反射和序列化攻击所困扰。
4. 通过私有构造器强化不可实例化的能⼒
⼀些类是不希望其他类对它实例化的,⽐如java.util.Arrays、java.lnag.Math、java.util.Collections。我们发现这些类都会声明⼀个私有的构造⽅法,这样外界就⽆法通过默认⽆参的构造⽅法来创建这些类的对象,同时这些类也不能被继承。