effective java
1、复合优先于继承 1.1 继承是实现代码重用的有力手段,但不总是完成这项工作的最佳工具。包的内部继承加上文档说明在一个程序员的控制下是非常安全的 但是越包边界的继承,则是很危险的。造成子类脆弱性的原因是,父类在后续版本获得新的方法,子类很有可能调用旧的方法。 1.2 为了解决上面的问题,可以考虑采用“复合”的方式,在一个新类中增加一个私有对象,通过构造函数传入,为了更加灵活,可以让他的类型为接口(比如Set,那么它可以接受TreeSet,HashSet等)。 1.3 如果让类B扩展类A,满足每一个B确实是A,则采用继承,否则采用复合模式。 1.4 继承机制的功能非常强大,但是也存在很多问题,因为它违背了封装原则。只有子类和超类之间存在子类型关系时,使用继承才是恰当的。如果不在同一包章,并且超类并不是为了扩展而设计的,那么继承将会导致脆弱性。 2.接口优于抽象类 2.1 明显区别:抽象类允许包含方法的实现,但接口不允许。 2.2 java只允许单继承,所以抽象类作为类型定义受到了很大的限制。 2.3 常量接口模式是对接口的不良使用。 3.优先考虑静态成员类 3.1 嵌套类是指被定义在另一个类的内部的类,包括四种:静态成员类,非静态成员类,匿名类和局部类。除了静态成员类,其他三个都被称为内部类。 3.2 如果成员类的每个实例都需要一个指向其外围的引用,则把成员类做成非静态的,否则就做成静态的. 3.3 如果一个i额嵌套类属于一个方法的内部,并且只需要在一个地方使用和已知类型就做成匿名类,否则就做成局部类. 4.谨慎的使用重载 4.1 对于重载方法的选择是静态的,而对于被重写方法的选择是动态的。 5.返回0长度数组而不是null 5.1 原因每次用到该方法时都需要判断是否为null. 6.局部变量的作用域最小化 6.1 在第一次使用它的地方声明. 6.2 如果在循环终止之后循环变量的内容不再被需要的画,则for循环优于while循环.前者的变量作用域在for循环内,出现"剪贴-粘贴"的错误比较小. 6.3 for(int i=0,n=list.size();i<n;i++)比for(int i=0;i<list.size();i++)效率高,前者每次循环时不再需要调用集合的size方法. 7.了解和使用库 7.1 Random.nextInt(int),Arrays.asList(T),Collections.sort(v). 8.如果要求精确的答案,请避免使用float和double 8.1 它们没有提供完全精确的结果,不应该使用在要求精确的场合,比如货币计算。可以考虑使用BigDecimal,int或者long。 8.2 BigDecimal的缺点:一个是操作不方便,另一个则是很慢。 8.3 如果性能关键并且不介意自己处理十进制小数点,当数据不超过9位十进制时使用int,当数据不超过18位十进制时使用long,超过18位就只能使用BigDecimal。 9.如果其他类型更适合,则尽量避免使用字符串 9.1 比如接收的数字类型,但是是以字符串的形式传递的,应该将它转换成数字类型。 10.字符串连接性能 10.1 当两个字符串被连接的时候,它们的内容都要被拷贝,字符串不可变。 10.2 遇到多字符串拼接时,使用StringBuffer效率更高。 11.通过接口引用对象 11.1 优先考虑用接口作为类型. 12.对共享可变数据的同步访问(加同步锁) 12.1 避免过多的同步. 12.2 一个被同步的代码块中调用外部提供的方法(这个方法假如又开一个线程,它的锁和正在执行的代码块的锁一样)会引起死锁。解决它的方法很简单,将调用外部的方法移动到同步代码块的外面。 12.3 在同步区域内应该尽可能少的工作。 13.谨慎的使用Serializable接口 13.1 每一个被序列化的类都会生成一个标识符,也可以称为序列版本,它会受到类名,接口,方法等改变而改变。 13.2 一旦被序列化的类被发布,则“改变这个类的实现”的灵活性将大大降低。因为要支持原来的序列化形式。 13.3 增加了错误(bug)和安全漏洞的可能性。