人们常常看到变量应该用某个接口声明的建议,而不是实现类.例如:
List<Integer> list = new ArrayList<>();
但是,我说这个列表使用的算法确实依赖于ArrayList的O(1)随机访问(例如Fisher-Yates shuffling).在这种情况下,ArrayList为我表示的关键抽象是它的类似数组的性质,而不仅仅是它的List性质.换句话说,如果有人出现并将列表更改为LinkedList,这将是有问题的,即使代码将编译.在这种情况下,声明是否可以使用实现类型?,例如:
ArrayList<Integer> list = new ArrayList<>();
解决方法
要强调Oliver Charlesworth在评论中所说的内容:这些信息是否公开是最重要的区别.
从编写问题的方式来看,似乎你在谈论一个字段(而不是方法参数或返回值).根据定义,私有字段是一个实现细节,您可以任意具体.因此将它声明为ArrayList是可行的 – 尽管严格来说,这是不相关的.用这句话来表达:你说
if someone … changed
list
to aLinkedList
,this would be problematic,…
可以改变声明的人
private List<T> list = new ArrayList<T>();
至
private List<T> list = new LinkedList<T>();
也可以改变声明
private ArrayList<T> list = new ArrayList<T>();
至
private LinkedList<T> list = new LinkedList<T>();
防止这种情况的唯一可行方法是将此(重要)实现细节添加为注释,例如:
/** * The list that stores ... whatever. * * This list should have a complexity of O(1) for random access,* because ... */ private final List<T> list = new ArrayList<T>();
(这也可以通过内部将列表传递给期望它是RandomAccess的方法来强制执行.这是由AlexR提出的,但是引用公共方法.对于私有方法,即使这样也不会阻止某人更改方法签名,如果没有记录要求RandomAccess的意图和原因).