- 浏览: 52992 次
- 性别:
- 来自: 佛山
最新评论
文章列表
4.18-4.19 使用接口
- 博客分类:
- Effective Java
与使用抽象类相比,使用接口的优点包括:
1.类更容易声明执行新的接口
2.接口更容易定义mixin,如同一个类可以实现Comparable、Iterable接口。在排序时,此类可视为Comparable类型,在迭代时,此类可视为Iterable类型
3.接口允许定义非层次化的类型框架,如一个人可以同时为歌手和作曲家,那么可让Person类同时实现Singer和SongWriter接口,而Singer和SongWriter接口直接没有任何层次关系
4.接口可提供更安全和更强大的功能,如帮助实现Wrapper
使用接口的缺点:
1.直接继承抽象类比实现接口更简单 ...
1.如果类的构造函数或可被覆盖的方法(使用public/protected修饰),调用了另一个可被覆盖的方法,那么必须使用文档说明前者是如何调用后者的,甚至可说明前者的具体内部实现。如4.16小节,应使用文档说明addAll()是如何调用add()方法的
注:一般方法的注射只应该说明此方法做什么(what),而不应该说明如何做(how)
2.父类可能提供protected的钩子(hook)方法,以便子类能够参与进父类的运算过程。应使用注释说明这些hook方法
3.在发布一个可被继承的父类前,建议写至少3个子类进行测试(应由父类开发人员以外的人编写)
4.在父类的构造 ...
使用继承可能破坏类的封装性,可能的问题包括:
1.子类必须知道父类的内部实现才能正确的进行覆盖,如以下父类:
public class Container {
private List<Object> elements=new ArrayList<Object>();
public boolean add(Object e){
return elements.add(e);
}
public void addAll(Collection<Object> c){
for(Object e:c)add(e);
...
4.15 最小化类的可变性
- 博客分类:
- Effective Java
Java里包含很多不可变的类,如String,Boolean,Integer,这些类的优点包括:
1.简单
2.线程安全
3.可作为Map的key或集合元素
创建不可变类的基本原则包括:
1.不提供任何可修改对象状态的方法,如setter方法
2.不能继承
3.使用final修饰所有属性
4.使用private修饰所有属性
5.不要引用任何可被外部修改的可变的对象(可引用此对象的clone版本)
6.不要返回任何可变的对象给外部引用
7.需要处理序列化创建不可变类的对象的问题(见后面章节)
一个简单不可变类的示例:
public class Complex ...
对本小节持保留意见
基本原则:
1.如果一个类需要被其它包的类访问,那么应提供accessor方法(getter/setter)
2.package-private,private的类无需提供accessor方法
3.可直接使用public final的属性
封装是OOP的特征之一,最小化类和成员的可访问性可提高封装度
JAVA的可访问性修饰符包括:
private: 仅能本类访问
package-private:默认(default)可访问范围,同一包类可访问
protected: 同一包类和子类可访问
public: 任何类都可访问
注:顶级(top-level)类或接口只能声明为public或package-private
基本原则:
1.如果一个顶级类仅被同一个包里的类访问,应使用package-private
2.如果一个顶级类 ...
TreeMap,TreeSet,Arrays,Collections可能调用实现了Comparable接口的对象的compareTo()进行自然排序。实现compareTo()与实现equals()基本原则类似,不同点包括:
1.如果传入的比较对象的类型与当前对象不同,应抛出ClassCastException
2.如果x.compareTo(y)==0,那么应该x.equals(y)==true
BigDecimal没有遵守规则2,以下测试将通过,这可能导致以下2个BigDecimal对象可以同时放入一个HashSet对象里(因为equals()返回false),但是 ...
总是覆盖toString()以返回用户可读的信息,注意的地方:
1.提供getter方法以单独获取toString()返回的数据,避免使用者解析toString()以获取数据
2.如果toString()返回的格式化的字符串,那么需提供注释说明,同时提供静态格式化方法
clone方法容易导致错误,一般不建议使用此方法,而是提供相应的构造函数或者静态工厂方法用于对象复制
Object的clone()是protected,并且直接抛出CloneNotSupportedException。子类如果要覆盖clone(),必须声明实现Cloneable接口。如果类声明实现Cl ...
Set,Map等类会首先调用对象的hashCode(),根据返回的hash值比较对象是否相同(一般情况下可提高性能)。如果两个对象返回的hash值相同,则再调用对象的equals()进行比较。
以下类覆盖了equals(),使用phoneNumber比较对象是否相同 ...
Object的equals()使用“==”进行比较。即如果2个对象具有相同的内存地址,那么这2个对象相同。
以下情况不需要覆盖equals():
1.类的每个实例本来就是唯一的,如Thread类
2.不关心类的实例逻辑上是否相等(logical equality),如一般不关心两个Random对象是否产生相同的随机数序列
3.父类的equals()适用于子类,则子类不用再进行覆盖。如AbstractList,AbstractMap的equals()适用于子类
4.类是private的,永远不需要调用equals()。但是建议仍覆盖equals()直接抛出异常 ...
不使用的理由:
1.不能确定finalize()什么时候被执行
2.不能保证finalize()一定会被执行
3.使用finalize()严重影响性能
4.如果执行finalize()抛出异常,异常被忽略(不会有任何提示),此方法立刻终止执行,导致对象状态不一致
在以下情况可以谨慎使用:
1.如InputStream,如果编程者忘记调用close(),可以在finalize()里调用close()释放资源
2.在finalize()里调用native peer(指JNI里与Java对象对应的本地对象)的方法释放本地资源
2.6 移除过时的对象引用
- 博客分类:
- Effective Java
如下代码(以下代码来自Effective Java一书):
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
ele ...
2.5 避免创建不必要的对象
- 博客分类:
- Effective Java
1.避免使用new String("hello")创建不必要的字符串对象(在Java里,字符串实现为常量,以上方式将创建不必要的字符串对象)。以下测试:
private String temp;
@BeforeClass
public void init(){
//初始化创建hello字符串对象,避 ...
2.4 禁止创建工具类实例
- 博客分类:
- Effective Java
使用以下方式不仅可以禁止创建工具类的实例,还可以禁止继承工具类
注:工具类指仅包含静态方法的类,如java.util.Collections
public class MyUtil {
private MyUtil(){
throw new IllegalAccessError();
}
}
使用final可禁止类被继承,使用abstract可禁止创建类的实例(仍可创建匿名对象)。但是不能同时使用final、abstract声明类。
2.3 使用单例
- 博客分类:
- Effective Java
以下单例模式利用JVM的类加载机制保证单例对象的线程安全和初始化(在第一次类被加载时,会初始化INSTANCE属性,进而创建单例对象)
public class SingletonOne {
//在类加载后立即初始化
public static final SingletonOne INSTANCE=new SingletonOne();
private SingletonOne(){}
}
为了符合一般约定,也可以提供getInstance()方法返回单例对象
public class SingletonTwo {
private static final ...