1. 使用静态工厂代替构造,clone函数
原因
1. 静态工厂具有名字
i. 对于两个构造函数,如果参数类型和个数相同,则只能使用不同的顺序进行区分,而使用工厂函数可以为这两个构造函数指明不同的名称
ii. 如果有多个构造函数,可考虑用静态工厂方法替换
2. 不要求创建新对象
i. 当系统需要该类的N或1个实例,如果使用构造函数,则每次调用都会创建一个实例,可通过单例或多例模式重用已有实例
3. 返回原类型的子类型对象
i. 对于一个继承体系,在基类中声明静态工厂方法,根据type返回不同的子类实例,且该子类为package 或 private,可以向客户端隐藏子类。
命名规范
getInstance ,如 Interface newInstance(class a);代替clone
valueOf : 返回的实例与原有实例具有相同的值,如 Float和float , XXXConfig 和 XXX
1. equals 时
通用约定
对称性:如果x 和y属于不同的类,就要注意了
不需要对null做特殊的检查,null instanceof MyType 返回false
7. 改写equals要改写hashcode
Object中规范要求,如果equals返回true,则 两个对象的hashCode 产生相同的整数值,如果equals使用逻辑判断,而hashCode未改写(使用引用地址),该对象作为HashMap或HashSet 的key,equals相同的两个对象作为不同的key
编写方法:
1. 对每一个关键域(equals用到,而且非冗余)计算散列值 c
boolean : f?0:1;
byte char short int : (int ) f
long :(int) (f ^ (f >>>32))
float : Float.floatToIntBits(f)
double: Double.doubleToLongBits(f).floatToIntBits
对象引用,调用该对象的hashcode
2. 公式 17*37+c
3. 判断 hashCode和equals 方法是否一致
10. 考虑实现comparable
强烈建议满足 (x.compareTo(y)==0)==(x.equals(y)),否则如TreeSet中 equals不同而compareTo相同的对象只有一个
实现
直接进行类型转换,不进行类型和空判断
11. 使类和成员的可访问性最小
顶层类只有 default和public,尽量为default
成员(函数,属性,内嵌类)可以有 private default protected public四种,先都声明为private,在需要的时候修改
非零长度的数组总是可变的,所以具有公有的静态final数组域总是错误的,应该替换为一个方法,返回一个拷贝
12. 支持不可变性
1. 不提供修改方法
2. 该类不可继承 final
3. 所有域都是 private final
4. 如果类指向可变对象的引用,保证客户无法获得该引用
5. 如果类不能做成不变的,尽量限制其可变性,比如构造函数完成可变性创建
好处是:不要求线程同步
16. 接口优于抽象类
1. 防止构造层次结构的类型框架。 对于一个类体系,有基本的功能和扩展,对于这些基本功能应该通过继承实现,而可选的功能应该通过接口和实现类来引入
17. 接口只用于定义类型
常量不应该使用接口实现,如果该常量类枚举,应该使用 【类型安全枚举类】 来实现,否则使用不可被实例化的工具类 来定义这些常量
策略模式可以和简单工厂模式相结合,将具体的策略类实现为工厂的private static member class,对外部隐藏
18. 优先考虑静态成员类
嵌套类只定义在类内部,主要为父类服务,分为 static member class, nonstatic memeber class, annonymous class, local class.
成员类类似于普通的成员,可以访问父类的成员,包括声明为private的
选择:如果成员类的每个函数不需要访问外部类的非静态信息,则使用 static member class,否则为 nonstatic member class,如果该类只使用一次,且定义了接口或基类使用 annonymous class,local class只在方法内部定义的类,很少使用
static member class 为public,通常作为父类的一个子部分,如常量信息的存放;为private 通常作为父类的一个组件,比如Map和Map.Entity,而且该类不允许被外部访问,该类不能访问父类的非静态成员。
non static member class 多作为适配器,可以访问父类的非静态成员。
当选择时,考虑是否需要访问父类的非静态成员,不需要就是用static member class
21. 用类来代替enum
定义一个类来代替枚举类型,该类私有构造函数,
为每一个枚举常量定义 final static的对象,如public static final Suit CLUBS=new Suit("club");
调用时 Suit.CLUBS。
23. 检查参数的有效性
被外部调用的方法,使用异常标示参数非法,如IllegalArgumentException NullPointerException IndexOutOfBoundsException.
非公有的 使用assert处理
有些参数,方法本身不使用,存储起来以后使用,检测尤为重要,如构造函数
当参数检查非常昂贵,或者不切实际时,就不要参数检查了
26. 谨慎地使用重载
重载方法的调用是在编译期决定的,如 fun(Set s) , fun(Collection c)。 实参为 Collection[] tests=new Collection[] {new HashSet() }; 如果你以为会调用fun(Set s) 那就错了,因为是在编译期决定,而参数类型是Collection,所以会调用 fun(Collection c).
这种使用方式容易混淆,所以应该避免参数为同一体系的重载用法,或者更严格点,避免两个相同参数数目的重载方法
27. 返回零长度的数组而不是null
函数 Cheese[] getCheeses() 返回 new Cheese[0] 而不是null,好处有二,1. 符合逻辑需要 ; 2. 不需要对null额外处理
如果函数中用到多次 new Cheese[0],可以将其声明为常量 final static Cheese[] NULL_CHEESE_ARRAY=new Cheese[0] 然后在函数中使用。
29. 将局部变量的作用域最小化
当循环判断中涉及到一个方法调用,且可以保证每次迭代中这个方法调用返回相同的结果,则使用 for(int i=0, n=list.size; i<n;i++)将调用放在第一个;中
38. 遵守命名规范
常用的已经在 命名规范 中描述,下面说些特殊的
1. 转换对象类型的方法 toType ,如 toArray
2. 返回对象的一种表现形式 asType,如 asXML
3. 返回对象同值的primitive类型 typeValue 如 intValue
4. 静态工厂: valueOf (返回的实例与原有实例具有相同的值) 和 getInstance()
5. boolean 类型的变量和函数很类似,不过是省略了is,如 initialized和 isInitialized