Effective Java 精简实用版

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值