从抽象集合转换为具体集合¶
ID: java/abstract-to-concrete-cast
Kind: problem
Security severity:
Severity: warning
Precision: very-high
Tags:
- reliability
- maintainability
- modularity
- external/cwe/cwe-485
Query suites:
- java-security-and-quality.qls
Java 标准库中的大多数集合都由抽象接口(例如 java.util.List
或 java.util.Set
)定义,该接口由一系列具体类和一系列包装器实现。通常,除了构造对象时,最好使用抽象类型,因为这避免了对实现方式的假设。
从抽象集合转换为具体集合会使代码变得脆弱,因为它确保代码仅适用于一个可能的实现类,而不适用于其他类。通常,此类转换要么表明过度依赖具体实现类型,要么表明使用了错误的抽象类型。
建议¶
通常最好在变量、字段和参数声明中始终如一地使用抽象类型。
可能会有个别例外。例如,当迭代顺序很重要并且只有 LinkedHashSet
实现提供正确行为时,通常将变量声明为 LinkedHashSet
而不是 Set
。
示例¶
以下示例说明了使用错误抽象类型的情况。 List
接口不提供 poll
方法,因此原始代码将 queue
转换为提供此方法的具体类型 LinkedList
。若要避免这种向下转换,只需为此方法使用正确的抽象类型,即 Queue
。这记录了程序员的意图,并允许此方法的客户端使用各种队列实现。
Customer getNext(List<Customer> queue) {
if (queue == null)
return null;
LinkedList<Customer> myQueue = (LinkedList<Customer>)queue; // AVOID: Cast to concrete type.
return myQueue.poll();
}
Customer getNext(Queue<Customer> queue) {
if (queue == null)
return null;
return queue.poll(); // GOOD: Use abstract type.
}
参考¶
J. Bloch,Effective Java(第二版),第 52 条。Addison-Wesley,2008 年。
Java API 规范:Collection。
常见弱点枚举:CWE-485。