使用Collection接口创buildArrayList对象的多态性有什么好处?
我研究了多态,并且明白它可以做如下的dynamic方法绑定。
假设动物类是抽象类。
public class AnimalReference { public static void main(String args[]) Animal ref // set up var for an Animal Cow aCow = new Cow("Bossy"); // makes specific objects Dog aDog = new Dog("Rover"); // now reference each as an Animal ref = aCow; ref.speak(); ref = aDog; ref.speak(); }
我用来创buildArrayList的实例,如:
ArrayList myList = new ArrayList();
但通常我觉得人们写道:
Collection myList = new ArrayList();
所以我的困惑是声明为集合的好处是什么? 另外我不知道你可以在“myList”前面有“Collection”(这是一个不是抽象类的接口)。
为什么说不好的做法是:
ArrayList myList = new ArrayList();
我读的集合接口和ArrayList的Java文件以及在线教程,但仍然不是很清楚..任何人都可以给我一些解释?
如果将myList
声明为ArrayList
,则修复其具体types。 每个使用它的人都将依赖于这个具体types,而且很容易(甚至是无意中)调用ArrayList
特有的方法。 如果稍后您决定将其更改为例如LinkedList
或CopyOnWriteArrayList
,则需要重新编译(甚至可能更改)客户端代码。 接口编程消除了这种风险。
请注意, Collection
和ArrayList
之间还有另一个抽象层次: List
接口。 通常,列表的使用模式与地图,集合或队列的使用模式非常不同。 所以你需要一个工作的收集types通常是早期决定的,不会改变。 将variables声明为List
将清晰地表明这一决定,并为客户提供有关该集合遵守的合同的有用信息。 Collection
OTOH通常不是非常有用,而不是遍历其元素。
编写List<Something> myList = new ArrayList<Something>();
可能更常见List<Something> myList = new ArrayList<Something>();
比使用Collection
。 通常它的一些方面是很重要的。 Collection
对于接受重复元素(无论是集合还是列表(或其他))的模糊性可能是一种痛苦。
除此之外,主要目的是抽象或实现独立性。 我真的在意我的List是ArrayList
还是Vector
? 可能不是大部分时间。 我的代码更灵活,如果它使用最普通的接口来expression我需要的对象。
简单的例子是,假设你使用所有的ArrayList
来编写一个程序,然后它需要支持多个用户,所以为了线程安全,你想把所有的ArrayList
都改成Vecto
rs。 如果你一直在引用typesArrayList
引用,你必须改变每一个用处。 如果你一直在引用typesList
,你只需要改变你创build它们的地方。
另外,有时候实现类可能不是您可以或想要导入和使用的东西。 例如,当使用像hibernate这样的持久化提供程序时,实现Set
接口的实际类可以是框架特有的高度专门化的自定义实现,也可以是普通的旧HashSet
,具体取决于如何创build对象。 你不在乎差异,这只是一个给你。
如果你声明一个ArrayList
,我不会使用ArrayList
作为左侧的types。 相反,编程接口,无论是List
或Collection
。
请注意,如果您将一个方法声明为一个Collection
,它可以通过一个List
或Set
。
作为一个侧面说明,考虑使用generics 。
编辑:话虽如此,generics还介绍了一些问题。
List<Animal>
可以存储ArrayList<Animal>
,但不能存储ArrayList<Cat>
。 你需要List<? extends Animal>
List<? extends Animal>
来存储一个ArrayList<Cat>
。
首先,inheritance和接口之间有明显的区别。 简短的回溯历史:在普通的旧c ++中,你可以从多个类inheritance。 如果一个“Transformer”类inheritance自“Vehicle”和“Human”,它们都实现了一个名为“MoveForward”的方法,这会带来负面的后果。 如果您在“Transformer”类中调用此方法,那么该实例使用哪个函数? “人”还是“车”的实施? 解决这个问题的接口是由java,c#,…引入的。 接口是你的课程和其他东西之间的契约。 您对function做出了承诺,但是合同并没有为您的类实现任何逻辑(以防止Transformer.MoveForward问题)。
一般多态性意味着某种东西可能以不同的方式出现。 “变压器”可以是“车辆”和“人”。 根据你的语言(我使用C#),你可以实现“MoveForward”的不同行为,取决于你想要履行的合同。
使用接口而不是具体的实现有几个优点。 首先,您可以切换实现而不更改代码(用于Google查找的dependency injection;)。 其次,您可以使用testing框架和模拟框架更轻松地testing您的代码。 第三,使用最通用的接口数据交换(列表的枚举器instad,如果只想交换值)是一个很好的做法。
希望这有助于理解接口的优点。
你在局部variables声明中使用的types(如你的ArrayList例子中)通常不是那么重要。 所有你必须确保的是myList的types(名字'myList'左边的单词)必须比使用myList的任何方法参数的types更具体。
考虑:
ArrayList words = new ArrayList(); sort(words); removeNames(words); public void sort(Collection c) ... blah blah blah public void removeNames(List words) ...
我可以将“单词”的typesreplace为List。 这对我的程序的可读性或行为没有任何影响。 虽然我不能将“单词”定义为Object。 这太笼统了。
在相关说明中,当你定义一个公共方法时,你应该仔细考虑方法参数的types,因为这对调用者可以传入的东西有直接的影响。如果我定义了不同的sorting:
ArrayList words = new ArrayList(); // this line will cause a compilation error. sort(words); public void sort(LinkedList c) ... blah blah blah
sorting的定义现在非常严格。 在第一个例子中,sort方法允许任何对象作为参数,只要它实现了Collection。 在第二个例子中,sort只允许一个LinkedList,它不会接受任何其他的东西(ArrayLists,HashSets,TreeSets等等)。 sorting方法可以使用的场景现在非常有限。 这可能是有原因的; sorting的实现可能依赖于LinkedList数据结构的一个特性。 如果使用这个代码的人需要一个适用于LinkedLists以外的sortingalgorithm,那么定义这种sorting方法只是不好的。
编写Java库的主要技能之一是决定方法参数的types。 你想成为多么一般的人?
那么,一个arraylist有一个dynamic的大小。 该集合没有编译时间检查,它必须被投入input。 一个集合只包含通过引用的对象。 你可以把collections当成一个“包”。 操纵可以在整个对象上执行。 我也确定,与ArrayList相比,收集的search时间较短,但不是肯定的。 ArrayLists具有更多可以调用的function和方法。
通过声明和使用myList
作为一个集合,你隐藏了你正在做的实现select(在这种情况下,它被表示为一个ArrayList)。 一般来说,这意味着任何依赖于你的代码段的东西只会依赖myList作为一个集合,而不是作为一个ArrayList。 这样,如果您决定以后再将其表示为一个“Set?A Linked List?”,则不会破坏其他任何内容。
Collection
是ArrayList
的超types。 如果您只需要Collection
提供的function,那么这是一个很好的做法,因为您明确指出了variables声明中需要哪些function。 你在初始化中select一个ArrayList
是无关紧要的(虽然是一个很好的默认select)。 它是一个Collection
的声明告诉你和任何未来的编码器,你正在关心什么合同。