JAVA学习之 Effective JAVA (读书笔记)
2008-04-01 15:20
260 查看
EFFECTIVE JAVA 学习笔记
... 21
优点:
1. 工厂方法带有名字
2. 不必每次调用都实例化对象(更为灵活、尤其适用于不可变类)
3. 能够返回任意子类对象(适用于基于接口的框架,如集合框架、以及更为灵活的服务提供者框架, 如JCE)
缺点:
1. 如不提供公共或受保护的构造函数则不能被子类化(继承)
2. 难以同其他的静态方法区分(采用命名约定有一定效果)
1. 采用公共静态成员变量+类静态初始化
2. 采用私有静态成员+静态工厂方法(更为灵活)。
优点:
1. 保证类不可实例化,达到仅提供工具函数的目的,同时也保证不被继承(导致子类实例化)
缺点:
1. 容易滥用,导致过程式编程
优点:
1. 减少冗余、提高了复用,同时性能也大为提升(尤其适用于不可变对象)
优点:
1. 减少内存泄露,提高性能
1. 不能保证及时执行
2. 不能依赖其保证持久状态
不进行重写的情况:
1. 类的实例独一无二
2. 并不需要类进行逻辑相等测试
3. 超类已经提供可用equals()方法
4. 类为私有类(重写为抛出异常)
重写时遵守的协议:
1. 反身性
2. 对等性
3. 传递性
4. 一致性
5. 非空性
高质量equals()方法的特征:
1. 使用==操作符先行测试
2. 使用instanceof操作符测试
3. 使用cast进行类型转换
4. 相应字段进行相等性测试
5. 进行对等性、传递性、一致性
重写equals()方法时的注意事项:
1. 重写equals()方法时重写hashCode()方法
2. 不要过于聪明
3. 不要依赖不可靠资源
4. 不要子类化参数类型
重写时遵守的协议:
1. 相等测试字段不变时,hashCode()方法返回相同整数
2. 相等的两个对象返回相同的hashCode整数
3. 不相等的两个对象也可能产生相同的hashCode整数
4. 可以通过一个私有字段缓存hashCode值
构建Hash函数的基本步骤:
1. 存储非零整数值如17到整形变量result
2. 计算相关字段对应的hash值c
3. result = 37*result + c
4. 返回result
5. 测试是否相等对象拥有相同hash值
优点:
1. 更为方便使用、更为清晰
重写toString()时的注意事项:
1. 应该包含对象中的所有有意义的信息
2. 注释文档的意图(不管采用特定格式与否)
3. 方法返回的值最好能够编程访问
优点:
1. 提供更为灵活的clon()方法实现
2. 能够充当构造函数
实现compareTo()方法时遵守的规范:
1. 对称性
2. 传递性
3. 等值性
4. 相等性
5. 方法在比较不同类对象时抛出异常
最小化原则:
1. 尽可能使得类或成员不可访问
2. 顶层类尽可能提供包私有访问
3. 成员尽可能提供私有访问
4. 不要提供public静态数组字段
类不可变的五大原则:
1. 不提供修改对象的方法
2. 方法都不能被复写
3. 字段均为final型
4. 字段私有
5. 排除对可变组件的访问
优点:
1. 简单
2. 线程安全
3. 自由共享
4. 为其他对象提供大型构建快
缺点:
1. 每个值都得提供一个对象
总结:
1. 尽量使得类不可变
2. 限制类的可变性
3. 构造函数提供对像创建的所有信息
1. 破坏了封装
2. 容易导致过深的继承层次
1. 必修对重写任何方法的效果进行精确的注释
2. 类可能必修通过受保护的方法提供到内部工作的钩子
3. 构造函数禁止调用(直接、间接)可重写的方法
4. 将readResolve方法或writeReplace方法设为受保护的
5. 设计一个用于继承的类添加了子类化限制
6. 适当的时候应当禁止子类化
2. 接口是定义“微类型”的理想选择
3. 接口允许非继承的类型层次结构
4. 接口保证了安全、强大的功能增强
5. 抽象类比接口更容易演化(例外)
1. 静态成员类
2. 非静态成员类
3. 匿名类
4. 本地类
1. 对公用方法用throws注释
2. 内部方法通过assert结构强化处理
总之,写方法是应该认真考虑参数的限制、予以注释并进行相应的检查。
2. 不要在提供便利方法上走过头
3. 避免长参数列表
4. 对于参数类型,青睐接口而非类
5. 谨慎使用功能对象
2. 重载方法的选择是静态的、重写方法的选择是动态的
3. 要避免重载方法的混淆
4. 不要导出两个参数数相同的重载方法
2. 以一致的规范编写注释
1. 当局部变量第一次使用时,声明局部变量
2. 几乎每个局部变量的声明都应同时初始化
3. 循环变量最好置于FOR循环之中
4. 保持方法的短小精悍
1. 应用库你就利用了专家知识和前人的经验
2. 应用库也节约了开发时间
3. 易于掌握新添特性
4. 降低了学习成本
5. 不用重新发明轮子
2. String不适于充当枚举类型的替代物
3. String不适于充当聚合类型的替代物
4. String不适于充当功能的替代物
5. 更好的类型存在或能构造时,不要使用String
2. 用StringBuffer
2. 应用接口,程序更为灵活
3. 不存在接口类型才使用类引用对象
1. 失去了编译期类型检查
2. 不容易书写、繁杂
3. 性能损耗
作为规则,运行时对象不应当以反射的方式访问。总之,反射一般仅用于初始化对象,除非对象完全不可知(接口类型都不存在)。
1. 异常处理的代价高昂
2. JVM优化
3. 用异常进行边界检查没必要
4. 异常不应当用于正常的控制流
5. 设计良好的API不应当让用户处理正常控制异常
异常的使用时机:
1. 当调用者被期望从异常状况中恢复时使用受检异常
2. 使用运行时异常指明程序错误
3. 所有的非受检异常都应该继承自RuntimeException
1. 异常状况不能通过API的适当使用避免
2. 开发人员希望进行额外的处理
1. API学习成本更低
2. 程序更易阅读
3. 更少的类、更快的类加载
常用的标准异常:
1. 非法参数异常
2. 非法状态异常
3. 空指针异常
4. 下标越界异常
5. 同步修改异常
6. 不支持操作异常
2. 使用@throws注释非受检异常,但不包含在方法声明中
3. 一个异常因同一原因在类的多个方法出现,则最好在类级别注释该异常
1. 不可变对象
2. 调用前参数校验
3. 排序计算,将修改置于发生失败的计算之后
4. 工作于对象的临时拷贝
2. 作为规则,尽量保持同步代码的短小。
2. 线程优先级是JAVA平台中最不具备移植性的特性
3. Thread.yield方法仅用于提高测试时的并发量
1. 同步代码是实现细节,并非导出API的一部分
2. 为保证安全的多线程使用,类必须在规格层面指明其支持的线程安全性
2. 线程组在线程安全方面很弱
3. 线程组基本上是多余的
... 21
第一章 绪论
第二章 创建和销毁对象
Item 1:考虑采用静态工厂方法替代构造函数
JAVA SE范例:原生基本类型的包装类优点:
1. 工厂方法带有名字
2. 不必每次调用都实例化对象(更为灵活、尤其适用于不可变类)
3. 能够返回任意子类对象(适用于基于接口的框架,如集合框架、以及更为灵活的服务提供者框架, 如JCE)
缺点:
1. 如不提供公共或受保护的构造函数则不能被子类化(继承)
2. 难以同其他的静态方法区分(采用命名约定有一定效果)
Item 2:通过私有化构造函数保证单件特性
实现单件有两种方式:1. 采用公共静态成员变量+类静态初始化
2. 采用私有静态成员+静态工厂方法(更为灵活)。
Item 3:通过私有构造函数保证类不可实例化
JAVA SE范例:数学、集合等实用工具类优点:
1. 保证类不可实例化,达到仅提供工具函数的目的,同时也保证不被继承(导致子类实例化)
缺点:
1. 容易滥用,导致过程式编程
Item 4:避免创建冗余对象
JAVA SE范例:基本对象的包装类优点:
1. 减少冗余、提高了复用,同时性能也大为提升(尤其适用于不可变对象)
Item 5:消除孤立的对象引用
JAVA SE范例:堆栈的数组实现方式优点:
1. 减少内存泄露,提高性能
Item 6:避免使用Finalizer
缺点:1. 不能保证及时执行
2. 不能依赖其保证持久状态
第三章 所有对象通用的方法
Item 7:重写equals()方法时遵守通用协议
JAVA SE范例:线程、随机、集合等类。不进行重写的情况:
1. 类的实例独一无二
2. 并不需要类进行逻辑相等测试
3. 超类已经提供可用equals()方法
4. 类为私有类(重写为抛出异常)
重写时遵守的协议:
1. 反身性
2. 对等性
3. 传递性
4. 一致性
5. 非空性
高质量equals()方法的特征:
1. 使用==操作符先行测试
2. 使用instanceof操作符测试
3. 使用cast进行类型转换
4. 相应字段进行相等性测试
5. 进行对等性、传递性、一致性
重写equals()方法时的注意事项:
1. 重写equals()方法时重写hashCode()方法
2. 不要过于聪明
3. 不要依赖不可靠资源
4. 不要子类化参数类型
Item 8:重写equals()时总重写hashCode()方法
JAVA SE范例:HashMap、HashTable、HashSet重写时遵守的协议:
1. 相等测试字段不变时,hashCode()方法返回相同整数
2. 相等的两个对象返回相同的hashCode整数
3. 不相等的两个对象也可能产生相同的hashCode整数
4. 可以通过一个私有字段缓存hashCode值
构建Hash函数的基本步骤:
1. 存储非零整数值如17到整形变量result
2. 计算相关字段对应的hash值c
3. result = 37*result + c
4. 返回result
5. 测试是否相等对象拥有相同hash值
Item 9:总是重写toString()方法
JAVA SE范例:Object对象的toString()方法优点:
1. 更为方便使用、更为清晰
重写toString()时的注意事项:
1. 应该包含对象中的所有有意义的信息
2. 注释文档的意图(不管采用特定格式与否)
3. 方法返回的值最好能够编程访问
Item 10:谨慎地重写clon()方法
JAVA SE范例:Clonable接口优点:
1. 提供更为灵活的clon()方法实现
2. 能够充当构造函数
Item 11:考虑实现Comparable接口
JAVA SE范例:List、Array等有序集合实现compareTo()方法时遵守的规范:
1. 对称性
2. 传递性
3. 等值性
4. 相等性
5. 方法在比较不同类对象时抛出异常
第四章 类和接口
Item 12:最小化类及其成员的访问性
信息隐藏或封装是这一原则的基本概念,通过封装解藕模块关系。Java中内置有访问控制机制,提供private、protected、包访问等。最小化原则:
1. 尽可能使得类或成员不可访问
2. 顶层类尽可能提供包私有访问
3. 成员尽可能提供私有访问
4. 不要提供public静态数组字段
Item 13:青睐不可变性
JAVA SE范例:String、包装类等类不可变的五大原则:
1. 不提供修改对象的方法
2. 方法都不能被复写
3. 字段均为final型
4. 字段私有
5. 排除对可变组件的访问
优点:
1. 简单
2. 线程安全
3. 自由共享
4. 为其他对象提供大型构建快
缺点:
1. 每个值都得提供一个对象
总结:
1. 尽量使得类不可变
2. 限制类的可变性
3. 构造函数提供对像创建的所有信息
Item 14:青睐组合多于继承
继承的不足:1. 破坏了封装
2. 容易导致过深的继承层次
Item 15:继承的设计、编档与禁止
如何为了类的后续继承而设计、编档?1. 必修对重写任何方法的效果进行精确的注释
2. 类可能必修通过受保护的方法提供到内部工作的钩子
3. 构造函数禁止调用(直接、间接)可重写的方法
4. 将readResolve方法或writeReplace方法设为受保护的
5. 设计一个用于继承的类添加了子类化限制
6. 适当的时候应当禁止子类化
Item 16:相对抽象类偏好接口
1. 已经存在的类能够容易的实现一个新的接口2. 接口是定义“微类型”的理想选择
3. 接口允许非继承的类型层次结构
4. 接口保证了安全、强大的功能增强
5. 抽象类比接口更容易演化(例外)
Item 17:仅仅用于定义类型的接口
一个典型范例——常量接口,常量接口是接口的一个比较差的应用。总的来说接口不应当仅仅用于定义类型Item 18:青睐静态成员类而非非静态
JAVA中包含四种内联类:1. 静态成员类
2. 非静态成员类
3. 匿名类
4. 本地类
第五章 C构造的替代物
Item 19:用类替代结构
类相比于结构体现出更好的封装性,但有时基于性能的考虑也有例外。Item 20:类继承替代联合
Item 21:类替代枚举结构
C中的枚举仅定义了命名整数常量,JAVA中提供了新的类型安全枚举模式作为替代物。Item 22:用类和接口替代函数指针
第六章 方法
Item 23:检查参数的有效性
通常方法对传入的参数的有效性有一定约束,如索引越界、非法参数、空指针等。具体检测策略:1. 对公用方法用throws注释
2. 内部方法通过assert结构强化处理
总之,写方法是应该认真考虑参数的限制、予以注释并进行相应的检查。
Item 24:必要时进行防卫式拷贝
有必要进行防卫式编程,以保证不可变性,通常这需要通过防卫式拷贝予以实现。防卫式拷贝在参数有效性之前执行,并通常不使用Clon方法实现。Item 25:仔细设计方法签名
1. 仔细的选择方法名2. 不要在提供便利方法上走过头
3. 避免长参数列表
4. 对于参数类型,青睐接口而非类
5. 谨慎使用功能对象
Item 26:谨慎的使用重载
1. 编译期静态决定调用那个重载方法2. 重载方法的选择是静态的、重写方法的选择是动态的
3. 要避免重载方法的混淆
4. 不要导出两个参数数相同的重载方法
Item 27:返回零长数组而非NULL
Item 28:对所有的导出API注释
1. 方法的注释应该描述其功能及与客户的契约2. 以一致的规范编写注释
第七章 通用程序设计
Item 29:最小化局部变量的作用域
最小化局部变量作用域,增强了代码的可读性和可维护性、同时降低了犯错的几率。1. 当局部变量第一次使用时,声明局部变量
2. 几乎每个局部变量的声明都应同时初始化
3. 循环变量最好置于FOR循环之中
4. 保持方法的短小精悍
Item 30:了解并应用库
1. 应用库你就利用了专家知识和前人的经验
2. 应用库也节约了开发时间
3. 易于掌握新添特性
4. 降低了学习成本
5. 不用重新发明轮子
Item 31:如果要求准确的结果则避免用FLOAT和DOUBLE
FLOAT、DOUBLE型变量不适用于准确十进制计算,尤其在财务计算中,这是做好用BigDicimal等类型。Item 32:其他类型更合适时避免用String类型
1. String不适于充当其他值类型的替代物2. String不适于充当枚举类型的替代物
3. String不适于充当聚合类型的替代物
4. String不适于充当功能的替代物
5. 更好的类型存在或能构造时,不要使用String
Item 33:明了字符串连接的性能
1. 字符串连接符缺乏性能表现2. 用StringBuffer
Item 34:使用接口引用对象
1. 合适的接口存在,则优先使用接口2. 应用接口,程序更为灵活
3. 不存在接口类型才使用类引用对象
Item 35:相较于反射青睐接口
反射的缺点:1. 失去了编译期类型检查
2. 不容易书写、繁杂
3. 性能损耗
作为规则,运行时对象不应当以反射的方式访问。总之,反射一般仅用于初始化对象,除非对象完全不可知(接口类型都不存在)。
Item 36:谨慎使用JAVA本地方法
Item 37:谨慎地进行性能调优
Item 38:坚持一贯的命名惯例
第八章 异常
Item 39:仅当异常情况下使用异常
滥用异常进行程序流程控制的缺点:1. 异常处理的代价高昂
2. JVM优化
3. 用异常进行边界检查没必要
4. 异常不应当用于正常的控制流
5. 设计良好的API不应当让用户处理正常控制异常
Item 40:对可恢复状况使用受检异常、对程序错误使用运行时异常
JAVA中包含三种异常:受检异常、运行时异常、错误。异常的使用时机:
1. 当调用者被期望从异常状况中恢复时使用受检异常
2. 使用运行时异常指明程序错误
3. 所有的非受检异常都应该继承自RuntimeException
Item 41:避免不必要的受检异常
受检异常往往容易加重使用负担,强迫处理异常状况。仅当下列两种情况同时成立时,才使用受检异常:1. 异常状况不能通过API的适当使用避免
2. 开发人员希望进行额外的处理
Item 42:青睐标准异常
JAVA中提供了一系列的标准非受检异常,开发人员可以在适当的时机予以重用。重用标准异常的好处:1. API学习成本更低
2. 程序更易阅读
3. 更少的类、更快的类加载
常用的标准异常:
1. 非法参数异常
2. 非法状态异常
3. 空指针异常
4. 下标越界异常
5. 同步修改异常
6. 不支持操作异常
Item 43:抛出与抽象级适应的异常
JAVA中的异常链在进行异常传播时,通常对应着异常抽象级别的降低。高层应该捕获底层异常,抛出解释高层抽象的异常。Item 44:注释方法抛出的所有异常
1. 总是声明受检异常,并通过@Throws精确注释2. 使用@throws注释非受检异常,但不包含在方法声明中
3. 一个异常因同一原因在类的多个方法出现,则最好在类级别注释该异常
Item 45:在详细信息中包含失败捕获信息
JAVA中未捕获的异常将打出异常信息,该信息来自异常的toString方法。失败捕获信息中应该包含对异常有贡献的参数的值。Item 46:争取失败原子性
失败的方法调用应该将对象的状态恢复到调用之前——失败原子。达到失败原子性的途径:1. 不可变对象
2. 调用前参数校验
3. 排序计算,将修改置于发生失败的计算之后
4. 工作于对象的临时拷贝
Item 47: 不要忽略异常
通常,开发人员会通过一个空的catch快忽略异常,然而这通常并非所要的处理方式。这种方式违背了异常的目的——要求进行适当处理。至少,catch代码快应该包含为什么忽略异常处理的合理解释。第九章 线程
Item 48:共享可变数据的同步访问
线程神话:基于性能的考虑,应当避免使用原子数据的读写同步。同步在线程间通信和排除可变性一样是必修的。总之,只要多个线程共享可变数据,读写数据的线程就应该进行加锁。Item 49:避免越界的同步
1. 为避免死锁,不要在同步方法(代码快)内将控制转到客户端。2. 作为规则,尽量保持同步代码的短小。
Item 50:禁止在loop循环外调用wait方法
对象的wait方法用来让线程等待适当的条件,Wait方法的标准使用方法是:在被锁定对象的同步代码中调用。Wait方法的使用方式:总是在循环中调用wait方法,以等待特定条件成立。Item 51:不要依赖于线程调度
1. 依赖线程调度的程序更没有可移植性2. 线程优先级是JAVA平台中最不具备移植性的特性
3. Thread.yield方法仅用于提高测试时的并发量
Item 52: 注释线程安全性
类应该清楚的表明其线程安全性的原因:1. 同步代码是实现细节,并非导出API的一部分
2. 为保证安全的多线程使用,类必须在规格层面指明其支持的线程安全性
Item 53:避免线程组
1. 线程组没有提供任何的安全功能2. 线程组在线程安全方面很弱
3. 线程组基本上是多余的
第十章 序列化(略)
相关文章推荐
- JAVA内存泄露(Effective java学习)
- 【读书笔记】疯狂java讲义学习(三)—— 流程控制
- 学习java核心技术第3章的读书笔记
- 【读书笔记】疯狂java讲义学习(二)—— 数据类型和运算符
- 【读书笔记】疯狂java讲义学习(六)—— 面向对象(补充)
- 《Effective Java》学习心得——优雅而安全地构建Java对象
- [读书笔记]JAVA异常学习
- 新的一月,java好好学习一遍,每天坚持写笔记,还有读书笔记。
- Effective Java 读书笔记之java 序列化
- 【读书笔记】Java基础学习之目录
- Java7编程高手进阶读书笔记--final学习
- Effective Java 读书笔记或学习笔记
- 【Java数据结构学习笔记之一】线性表的存储结构及其代码实现
- java并发编程学习8--同步器--信号量
- Java学习笔记之Serializable接口
- java学习笔记15--引用传递
- [置顶] Java基础知识点学习笔记
- Java面对对象编程---学习笔记(序目)
- JAVA的学习 一
- Java学习笔记--数据类型