使用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特有的方法。 如果稍后您决定将其更改为例如LinkedListCopyOnWriteArrayList ,则需要重新编译(甚至可能更改)客户端代码。 接口编程消除了这种风险。

请注意, CollectionArrayList之间还有另一个抽象层次: 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。 相反,编程接口,无论是ListCollection

请注意,如果您将一个方法声明为一个Collection ,它可以通过一个ListSet

作为一个侧面说明,考虑使用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?”,则不会破坏其他任何内容。

CollectionArrayList的超types。 如果您只需要Collection提供的function,那么这是一个很好的做法,因为您明确指出了variables声明中需要哪些function。 你在初始化中select一个ArrayList是无关紧要的(虽然是一个很好的默认select)。 它是一个Collection的声明告诉你和任何未来的编码器,你正在关心什么合同。