EffectiveJava笔记(第一部分)

时间:2023-03-09 06:13:26
EffectiveJava笔记(第一部分)
考虑用静态构造方法代替构造器的好处:
1、静态构造方法有名字
    BigInteger.probablePrime(int, int, Random)比 new BigInteger(int, int, Random)更加清楚,从名字知道返回可能是素数。
    如果没有名字,将来给别人调用时,对方往往不知道该用哪个。
2、可以不必在每次调用时重新创建一个新对象
    其实就是享元模式和单例模式
3、可以返回原类型的任何子类型对象。
    这样可以使API变得更加简洁
    这里可以引申到“服务提供者框架模式”,类似于JDBC
4、创建参数化类型实例时,代码变得更简洁
    比如Map<String, List<String>> map = new HashMap<String, List<String>>();
    如果JDK有提供如下方法的话:
 public static <K, V> Map<K, V> newInstance(){
       return new HashMap<K,V>();
 }
可以直接Map<String, List<String>> map  = newInstance();

不过现在的JDK还没有这个方法。

考虑用静态构造方法代替构造器的坏处:
1、由于使用静态构造方法,会把原来的构造器去掉,造成这个类将无法被继承。
    不过这样倒也正好鼓励使用复合,而非继承。
2、它与其他普通的静态方法没有区别,文档或者一些工具,无法自动区分出这是构造方法。
    如果有人要查这个类的构造方法,将很难找。
参数多的时候,并且有些参数是可选的,builder模式更好
关于单例模式的强化:
传统的单例模式会被反射破坏掉,可以在构造器里计数,如果创建第二次则抛异常。
传统的单例模式会在序列化和反序列化之后变成两个,需要重写readResolve方法,返回原来的单例
单例模式的最佳方法:单元素枚举,可以解决上述两个问题。
避免创建不必要的对象:
1、比如,String s = new String("abc"); 应该改成 String s = "abc";
2、更倾向于使用静态构造器,比如:Boolean.valueOf(String)替代new Boolean(String),因为前者内部有复用对象,后者肯定会产生一个新对象。
3、明知不会改变的对象,要复用。比如判断时间是否落在某个起止时间之间,这里的起止时间是固定的,不需要每次判断时生成。
4、Map的keySet每次返回的是同一个Set,所以产生多个也没害处,却也是没有必要的。
5、优先使用基本类型(int),虽然包装类(Integer)用起来和基本类型几乎无差别,但其中隐式的包装和解包装会比较耗性能。
WeakHashMap : 当key被除了map本身引用之外,再无别的地方引用时,该key会被自动删除。
缓存以及回调等容易引起内存泄漏的地方,推荐使用WeakHashMap,弱引用的方式。
大部分情况下,避免使用finalizer方法:
1、因为finalizer方法被执行的时间是不确定的,甚至有可能根本不执行。
    比如在finalizer方法里做关闭文件的动作是错误的,因为对象失去引用后到执行finalizer的时间不确定,所以文件不会被及时关闭。
2、finalizer在不同JVM上执行的时机也未必相同。
    有可能在开发测试时的JVM上表现很好,但到了现场的JVM表现就很差,不稳定。
3、System.gc与System.runFinalization只能增加finalizer被执行的机会,但仍然是不确定的。
4、System.runFinalizationOnExit以及Runtime.runFinalizersOnExit能保证finalizer一定被执行,但这两个方法有致命缺陷,已经被废弃。
5、未被捕获的异常在finalizer过程中抛出是会被忽略的,甚至连警告都不会打印出来。
6、使用finalizer有一个非常严重的性能损失,创建和销毁对象比原来慢很多
不使用finalizer,可以使用显示的终结方法,典型的比如InputStream的close方法,要求调用者必须在结束时调用。
但finalizer可以充当显示终结方法的"安全网",在调用者忘记调用显示终结方法时,可以在finalizer里执行,因为这个时候调用者已经忘记了,即使finalizer的执行很不稳定,那也比没有关闭一些资源要好。比如FileInputStream就是采用这种“安全网”。
finalizer的另一个合理的用途是,对本地对象(native object)的回收资源,本地对象比较特殊,垃圾回收器是不会回收本地对象,所以需要调用finalizer来回收非关键资源。