目录
1.复合优先于继承
- 子类覆盖父类的方法,当父类或是超类对被继承的方法进行改动,或产生一个具有相同签名和返回类型的方法是,使用该方法的子类会被影响。
- 有一种办法可以避免前面提到的所有问题。即不扩展现有的类,而是在新的类中增加一个私有域,它引用现有类的一个实例。这种设计被称为“复合”( compos iti on)。
- 对于两个类A 和B ,只有当两者之间确实存在“ is-a ”关系的时候,类B 才应该扩展类A 。如果你打算让类B 扩展类A ,就应该问问自己:每个B 确实也是A 吗?
- 为了允许继承,类还必须遵守其他一些约束。构造器决不能调用可被覆盖的方法, 无论是直接调用还是间接调用。通过构造器调用私有的方法、final 方法和静态方法是安全的,这些都不是可以被覆盖的方法。(先对父类初始化构造器中调用被覆盖的子类方法此时未被子类初始化可能会出问题。
2.接口优于抽象类
- 抽象类单继承,接口类多继承
- java8以后缺省方法的出现允许给接口添加方法,缺省方法的调用注意线程安全问题(子类锁定迭代器,其他线程尝试修改),尽量避免利用缺省方法在现有接口上添加新的方法。
- 常量接口模式是对接口的不良使用。类在内部使用某些常量,这纯粹是实现细节。实现常量接口会导致把这样的实现细节泄露到该类的导出API 中。类实现常量接口对于该类的用户而言并没有什么价值。(用不可实例化的工具类来记录常量)
3.类层次优先于标签类
- 冗长的标签类对于修改扩展非常不便(类似于一个图形类里面既有各种形状的枚举,又有switch对于每种图形面积,周长的计算)每当我们添加新图形就要对所有的方法进行修改,不如采用继承的方式,公共的面积计算方法作为抽象类的抽象方法,不同的子类对其有不同的实现。我们可以时常考虑标签类是否可以重构到一个层次结构中。
4.静态成员类优于非静态成员类
- 嵌套类有四种: 静态成员类( static m巳mber class )、非静态成员类( nonstatic memb巳r class )、匿名类( anonymous class )和局部类( local class ) 。除了第一种之外,其他三种都称为内部类( inner class )。
- 如果嵌套类的实例可以在它外围类的实例之外独立存在,这个嵌套类就必须是静态成员类:在没有外围实例的情况下,要想创建非静态成员类的实例是不可能的。
- 如果声明成员类不要求访问外围实例,就要始终把修饰符static 放在它的声明中, 使它成为静态成员类,而不是非静态成员类。如果省略了static 修饰符,则每个实例都将包含一个额外的指向外围对象的引用。如前所述,保存这份引用要消耗时间和空间,并且会导致外围实例在符合垃圾回收时却仍然得以保留。由此造成的内存泄漏可能是灾难性的。
A a = new A();
A.c c = a.new C();
5.不要在一个java源文件中定义多个顶级类
6.尽量避免使用原生态类型
- Collection stamp=的声明可能出现集合内部插入不同元素的可能,运行时才能报错,Collection<Stamp>声明时指定集合类型插入其他元素编译会直接报错。
- 如果使用像List 这样的原生态类型,就会失掉类型安全性, 但是如果使用像List<Object >这样的参数化类型,则不会。
7.列表优于数组
Object[] obarray = new Long[1];
obarray[0] = "askdjaskldja";
第28 条:
但下面这段代码则不合法:
II Won ’ t compile!
List <Object> ol = new ArrayList<Long>();
al.add (”I don ’ t fit i n”) ;
- 从技术的角度来说,像E 、List<E >和List<String >这样的类型应称作不可具体化的( nonreifiable )类型[ JLS , 4.7 ]。直观地说,不可具体化的( non-reifiable )类型是指其运行时表示法包含的信息比它的编译时表示法包含的信息更少的类型,每当调用可变参数方法时,就会创建一个数组来存放varargs 参数。如果这个数组的元素类型不是可具体化的( reifialbe ),就会得到一条警告。利用Saf eVarargs 注解可以解决这个问题(详见第32 条) 。
- 当你得到泛型数组创建错误时,最好的解决办法通常是优先使用集合类型List<E>,而不是数组类型E [) 。这样可能会损失一些性能或者简洁性,但是换回的却是更高的类型安全性和互用性。
- 数组与泛型混合使用出问题,第一反应是列表替代数组。