一、泛型
1、请不要在新代码中使用原生态类型
(1)、JavaSE5增加泛型后,应该避免使用原生类型,如List。允许原生编译通过是为了兼容老版本。
(2)、泛型增强了编译器检查异常的能力。
(3)、使用原生态类型,会丢失泛型在安全性和表述性方面的所有优势。
(4)、泛型信息可以在运行时被擦除。
(5)、总结
原生态类型 List
泛型 List<E>
无限制通配符类型 List<?>
(显示的)参数化的类型 List<String>
有限制类型参数 <E extends Number>
递归类型限制 <T extends Comparable<T>>
有限制通配符类型 List<? extends Number>
泛型方法 static <E> List<E> asList(E[ ] a)
类型令牌 String.class
2、消除非受检警告
(1)、如果无法消除警告,同时可以证明引起警告的代码是类型安全的,此时可以用@SuppressWarnings("unchecked")注解来禁止这条警告。
3、列表优先于数组
(1)、泛型是不可变的(invariant),例如:List<Type1>既不是List<Type2>的子类型,也不是List<Type2>的超类。
(2)、数组是具体化的,数组在运行时才知道并检查它们的元素类型约束。泛型在编译时检查类型信息,并在运行时擦除元素的类型信息。擦除的目的是使泛型可以与没有使用泛型的代码随意进行互用。
(3)、数组和泛型不要混合使用。
4、优先考虑泛型
(1)、在新建类型时,为了确保它们不需要各种装换,把类做成泛型。
5、优先考虑泛型方法
(1)、静态工具类尤其适合泛型化。
6、利用有限制通配符来提升API的灵活性
(1)、在表示生产者或者消费者的输入参数上使用通配符类型,可以获取最大限度的灵活性。
(2)、PECS表示producer-extends,consumer-super。如果参数化类型表示一个T生产者,使用<? extends T>;表示一个T消费者,使用<? super T>。
(3)、不要用通配符类型作为返回类型。
7、优先考虑类型安全的异构容器
(1)、用key自身的class 类型作为key。因为Class 是参数化的类型,它可以确保我们使Context方法是类型安全的,而无需诉诸于一个未经检查的强制转换为T。这种形式的一个Class 对象称之为类型令牌(type token)。
public class Context {
private final Map<Class<?>, Object> values = new HashMap<>();
public <T> void put( Class<T> key, T value ) {
values.put( key, value );
}
public <T> T get( Class<T> key ) {
return key.cast( values.get( key ) );
}
}
二、枚举和注解
1、用enum代替int常量
(1)、int枚举是编译时常量,被编译到使用它们的客户端中,如果枚举常量关联的int发生变化,客户端必须重新编译。因此不安全。
(2)、枚举类型易读、安全,在装载和初始化枚举时会有空间和时间的成本。
(3)、多个枚举常量同时共享相同的行为,考虑使用策略枚举。
2、用标记接口定义类型
(1)、标记接口(marker interface):无方法声明的接口。
(2)、标记接口定义的类型是由被标记类的实例实现的。
(3)、如果想要定义类型,一定要使用接口。
三、序列序
序列化(serializing):将一个对象编码成一个字节流。反之为反序列化(deserializing)。
序列化技术为远程通信提供了标准的线路级(wire-level)对象表示法,也为JavaBeans组件结构提供了标准的持久化数据格式。
1、谨慎地实现Serializable接口
(1)、一旦一个类被发布,就大大降低了“改变这个类的实现”的灵活性。
(2)、代表活动实体的类,如线程池(thread pool),一般不应该实现Serializable。
(3)、为了继承而设计的类应该尽可能少地去实现Serializable接口,用户的接口也应该尽可能少地继承Serializable接口。
例外有,Throwable类实现了Serializable接口,所以RMI的异常可以从服务器端传到客户端。Component类实现了Serializable接口,因此GUI可以被发送、保存和恢复。HttpServlet类实现了Serializable接口,因此会话状态(session state)可以被缓存。
(4)、http请求时,controller层接收对象需要提供无参构造函数,方可序列化。
(5)、内部类的默认序列化形式是定义不清楚的,不应该实现Serializable。
2、考虑使用自定义的序列化形式
(1)、如果一个对象的物理表示法等同于它的逻辑内容,可能就适合于使用默认的序列化形式。例如:表示人名的类。
(2)、默认序列化形式缺点
- 它使这个类的导出API永远地束缚在该类的内部表示法上。
- 它会消耗过多的空间和时间。
- 它会引起栈溢出。
(3)、如果在读取整个对象状态的任何其他方法上强制任何同步,则也必须在对象序列化上强制这种同步。