EffectiveJava 学习记录 一

2017-07-04  本文已影响10人  渝中刘一手

第一章 前言

学习摘要

1.本书应该针对熟悉java程序设计语言的读者。
2.模块的用户应不应该被模块的行为所迷惑;模块要尽可能的小,但又不能太小(模块是指可重用的软件组建,从单个方法到包含多个包的复杂系统,都可以是一个模块) 代码应该被重用,而不是拷贝,尽量减少模块之间的依赖。
3.错误应该尽早的检测出来,最好是在编译的时刻。
4.Java支持四种类型:接口(interface),类(class),数组(array)和基本类型。前三种类型被称为引用类型,而基本类型的值不是对象。

第二章 创建和销毁对象

学习主题

 何时创建对象?
 何时避免创建对象?
 什么时候进行销毁?
 如何管理晓辉之前的各种清理操作?

学习摘要

********************************第一条*********************************************************
1. 考虑用静态工厂方法代替构造器  
----自我思考 将类中的方法定义为静态的,且可直接使用类名调用,无需实例化创建该类 (一般工具类可这样做)


比如:
public static Boolean valueOf(boolean b){
    return b?Boolean.TRUE:Boolean.FALSE; 
}
注意 静态工厂方法和和设计模式中的工厂方法有所不同

1 静态工厂方法与构造器不同的第一大优势在于 它们有名称:

解释: 比如有一个类PersonUtils(Person1 ,Person2) 该类会返回一个PersonUtils对象,对象中有一个成员变量是Person,这个类主要作用就是比较2个Person中谁的年龄更大一点,如果使用静态工厂方法 用getMaxAgeForPerson(Person1,Person2)来返回最大年龄的一个Person对象,显示得更加清楚。

2 静态工厂方法与构造器不同的第二大优势在于,不必每次调用它们的时候都要创建一个新的对象。

解释:比如Boolean.valueOf(boolean)方法,说明不必每次创建Boolean对象就可以使用该对象,并且从不用创建,如果程序经常创建相同的对象,并且创建的对象代价很高,使用静态工厂方法就可以很大的提升性能。

3 静态工厂方法与构造器不同的第三大优势在于 他们可以返回原返回类型的任何子类型的对象。
解释:P7页 见例子

4 静态工厂方法的第四大优势在于,在创建参数化类型实例的时候,他们是代码变得更加简单
解释:Map<String,String> map=new HashMap<String,String> ,因为HashMap实现了Map接口,所以不用在创建的时候实例化Map。这种被称为类型推导。

**缺点
1 静态工厂方法的主要缺点在于 类如果不含共有的或者受保护的构造器,就不能被子类化
2 静态工厂方法的第二个缺点在于 他们与其他的静态方法实际上没有任何区别
下面是静态工厂方法一些惯用的名称 (p8)
valueOf
of (valueOf更为简洁的替代)
newInstance (像getInstance一样 但是newInstance能够确保返回的每个实例都与其他实例不同)
getType 像getInstance一样 type表示工厂方法中所返回类的类型
newType 像newInstance一样 type表示工厂方法中所返回类的类型

********************************第二条*********************************************************

2 遇到多个构造参数是要靠与使用构建器
解释:由于静态工厂方法和构造器都有一个共同的局限性,就是不能很好的扩展到大量的可选参数,因此这里推荐使用Builder模式,不直接创建对象,让客户端自己去构建自己需要的参数,客户端调用无参的build来生成对象。
例子
public class Person {
private int age;
private String name;
private String sex;
private int height;

public static class PersonBuilder implements Builder<Person>{
    private int age=10;
    private String name;
    private String sex;
    private int height;
    public PersonBuilder setSex(String sex) {
        this.sex = sex;
        return this;
    }
    public PersonBuilder setHeight(int height) {
        this.height = height;
        return this;
    }
    
    @Override
    public Person build() {
        return new Person(this);
    }
    
}
private Person(PersonBuilder builder) {
    age=builder.age;
    name=builder.name;
}
}
使用的时候自己去构建自己想要的参数 比如
Person person=new Person.PersonBuilder().setHeight(170).setSex("女").build();


**Builder模式的不足
为了创建对象,比如要创建它的构造器,虽然在实践中创建构造器的开销不那么明显,但是在某些十分注重性能的情况下,可能就会出现问题。Builder模式比重叠构造器模式更加冗长,因此只有在参数很多的时候才使用  比如4个或者更多参数的时候。

总结:如果类的构造器或者静态工厂中有多个参数,可以考虑使用Builder模式,便于阅读和编写。



********************************第三条*********************************************************
3 用私有构造器或者美剧类型强化Singleton属性

主要常见于单列的实现



********************************第四条*********************************************************
4 通过私有构造器,强化不可实例化的能力
解释:
通过使用私有构造器,可以防止该类不集成,防止外部类访问或者实例化创建该类。



********************************第五条*********************************************************
5 避免创建不必要的类
解释:创建一个类的代价特别大 ,应该尽可能的避免创建对象 特别是一些创建后就不会发生变化的类。可以通过静态代码块的方式初始化该类,在使用的时候直接调用,不必每次调用的时候都去实例化该类(比如JDBC链接相关的)

**警告
通过维护自己的对象池来避免创建对象比不是一种好的做法,除非池中的对象是非常重量级的。(比如数据库中连接池 建立数据库链接的代价非常昂贵,所以重用这些对象是有意义的),一般而言,维护自己的对象池必定会吧代码弄得很乱,同时增加内存占用,还会损害性能。
同时应该创建新的对象的时候,不要重用以前的对象。



********************************第六条*********************************************************
6 消除过期引用 (p21)

解释:常见于数组中存放对象的时候,移除对象以后没有将对象原来的位置清空引用,导致了可能会被错误的引用,程序会引发空指针异常。
实例代码
public Object pop(){
        Object result=elements[--size];
        elements[size]=null;
        return result;
}
当对象被移除数组的时候,我们应该清除掉对应下标下的对象引用。防止被错误引用。

内存泄漏的另一个场景来源于缓存和监听,回调的使用。使用完毕之后应该记得解除掉监听器的使用。(p23)

*******************************第七条*********************************************************
7 避免使用终结方法(p24)
解释:终结方法不一定会被调用。如果一些重要的操作放到终结者方法中可能不会被调用容易引起一些问题,比如数据库连接池的关闭,如果放到finaly 终结者方法中如果被不调用,那么数据库连接将不会被关闭,容易引起内存泄漏的风险。而且使用终结者方法还有严重的性能损失。

**使用终结者方法的好处
可以充当安全网,在前面忘记显示终止的时候可以在finaly中关闭,晚点关闭总比不关闭好。
还有一个合理用途是与对象的本地对等体有关(p26 没理解,感觉好复杂。。)

2017/7/4 23:15:43

上一篇下一篇

猜你喜欢

热点阅读