简体   繁体   English

使用Collection接口创建ArrayList对象的多态性有什么好处?

[英]What is the benefit of polymorphism using Collection interface to create ArrayList object?

I studied polymorphism and understand that it can do dynamic method binding like below. 我研究了多态性,并了解它可以进行动态方法绑定,如下所示。

Assuming that class Animal is abstract class. 假设动物类是抽象类。

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();
}

I used to create instance of ArrayList like: 我曾经创建ArrayList的实例,例如:

ArrayList myList = new ArrayList();

But usually I figured that people write: 但通常我认为人们会这样写道:

Collection myList = new ArrayList();

So my confusion is what is the benefit of declaring as Collection? 所以我的困惑是声明为Collection有什么好处? Also I didn't know you can have "Collection" (which is an interface not abstract class) in front of "myList". 我也不知道您可以在“ myList”前面有“ Collection”(不是抽象类的接口)。

Why it is not good practice to just say: 为什么只说一遍不是好习惯:

ArrayList myList = new ArrayList();

I read Collection interface and ArrayList Java documents as well as online tutorials but still not really clear.. Could anyone give me some explanation? 我阅读了Collection接口和ArrayList Java文档以及在线教程,但仍然不太清楚。有人可以给我一些解释吗?

If you declare myList as ArrayList , you fix its concrete type. 如果将myList声明为ArrayList ,则修复其具体类型。 Everyone using it will depend on this concrete type, and it is easy to (even inadvertently) call methods which are specific to ArrayList . 每个使用它的人都将取决于此具体类型,并且很容易(甚至无意间)调用特定于ArrayList If sometime later you decide to change it to eg LinkedList or CopyOnWriteArrayList , you need to recompile - and possibly even change - client code. 如果以后某个时候决定将其更改为例如LinkedListCopyOnWriteArrayList ,则需要重新编译-甚至可能更改-客户代码。 Programming for interfaces eliminates this risk. 接口编程消除了这种风险。

Note that between Collection and ArrayList , there is another level of abstraction: the List interface. 请注意,在CollectionArrayList之间,还有另一个抽象层次: List接口。 Typically the usage pattern of a list is very different from that of a map, set or queue. 通常,列表的使用模式与映射,集合或队列的使用模式非常不同。 So the type of collection you need for a job is usually decided early on, and is not going to change. 因此,您通常需要尽早确定工作所需的收藏类型,并且不会改变。 Declaring your variable as a List makes this decision clear, and gives its clients useful information regarding the contract this collection obeys. 将变量声明为“ List可以使此决定变得清晰,并向其客户提供有关此集合遵守的合同的有用信息。 Collection OTOH is usually not very useful for more than iterating through its elements. 通常,OTOH Collection除了迭代其元素外,还没有什么用。

If you're declaring an ArrayList , I wouldn't ever use ArrayList as the type on the left side. 如果要声明ArrayList ,则永远不会将ArrayList用作左侧的类型。 Instead, program to the interface, be it List or Collection . 而是对接口进行编程,无论是List还是Collection

Note that if you declare a method as taking a Collection , it can be passed a List or Set . 请注意,如果将方法声明为采用Collection ,则可以将其传递给ListSet

As a side note, consider using Generics . 作为附带说明,请考虑使用泛型

Edit: Having said that, Generics also introduces some Gotchas. 编辑:话虽如此,泛型还引入了一些陷阱。

List<Animal> could store an ArrayList<Animal> , but not an ArrayList<Cat> . List<Animal>可以存储ArrayList<Animal> ,但不能存储ArrayList<Cat> You'd need List<? extends Animal> 您需要List<? extends Animal> List<? extends Animal> to store an ArrayList<Cat> . List<? extends Animal>以存储ArrayList<Cat>

It's probably more common to write List<Something> myList = new ArrayList<Something>(); List<Something> myList = new ArrayList<Something>();可能更常见List<Something> myList = new ArrayList<Something>(); than to use Collection . 而不是使用Collection Usually some aspects of it being a list are significant. 通常,列表的某些方面很重要。 The vagueness of Collection with regard to accepting duplicate elements whether it's a set or list (or whatever) underneath can be a pain. Collection在接受重复元素(无论是下面的集合还是列表(或其他))方面的含糊不清可能会很痛苦。

That aside, the primary purpose is abstraction, or implementation independence. 除此之外,主要目的是抽象或实现独立性。 Do I actually care if the List I have is an ArrayList or a Vector ? 我实际上是否在乎我拥有的列表是ArrayList还是Vector Probably not most of the time. 大概不是大多数时候。 My code is more flexible if it uses the most general interface that expresses what I need the object to do. 如果我的代码使用最通用的接口来表达我需要对象执行的操作,则它会更加灵活。

The easy example is, suppose you write a program using all ArrayList s, and then later it needs to support multiple users, so for thread safety you want to change all your ArrayList s to Vecto rs. 一个简单的例子是,假设您使用所有ArrayList编写程序,然后以后需要支持多个用户,因此出于线程安全的考虑,您希望将所有ArrayList都更改为Vecto rs。 If you've been passing around references to the Type ArrayList , you have to change every usage everywhere. 如果您一直在传递对Type ArrayList引用,则必须在各处更改每种用法。 If you've been passing around references to the Type List , you only have to change the places where you create them. 如果您一直在传递对Type List引用,则只需更改创建它们的位置。

Also, sometimes the implementing class might not be something you can or want to import and use. 另外,有时实现类可能不是您可以导入或使用的东西。 For example when using a persistence provider like hibernate, the actual class that implements the Set interface could be a highly specialized custom implementation unique to the framework, or it could be plain old HashSet , depending on how the object got created. 例如,当使用诸如hibernate之类的持久性提供程序时,实现Set接口的实际类可以是该框架唯一的高度专业化的自定义实现,也可以是普通的旧HashSet ,具体取决于对象的创建方式。 You don't care about the difference, it's just a Set to you. 您不在乎差异,它只是您的Set

Well, an arraylist has a dynamic size. 好吧,arraylist具有动态大小。 The collection has no compile time checking, it must be cast typed. 该集合没有编译时检查,必须强制转换类型。 A collection contains only objects by reference. 集合仅包含引用对象。 You can think of a collection as a "bag". 您可以将集合视为“包”。 And manipulation can be performed over the entire object. 并且可以在整个对象上执行操作。 I'm also sure that the searching time for a collection is short compared to an ArrayList, but not positive. 我还可以确定,与ArrayList相比,集合的搜索时间短,但不是肯定的。 ArrayLists have more functionality and methods that can be called. ArrayList具有更多可调用的功能和方法。

First of all there is a significant difference between inheritance and interfaces. 首先,继承和接口之间存在显着差异。 A short trip back history: In plain old c++ you where able to inherit from multiple classes. 简短的回顾历史:在普通的旧c ++中,您可以从多个类继承。 This had a negative consequence if a "Transformer" class inherits from "Vehicle" and "Human" both of them implementing a method called "MoveForward". 如果“ Transformer”类继承自“ Vehicle”和“ Human”两个类,并且这两个类都实现了称为“ MoveForward”的方法,则将产生负面影响。 Which function dshoud the instance use if you call this method on the "Transformer" class? 如果您在“ Transformer”类上调用此方法,则实例应使用哪个函数? the "Human" or the "Vehicle" implementation? “人类”还是“车辆”实施? To solve this problem interfaces are introduced by java, c#, ... . 为了解决这个问题,java,c#,...引入了接口。 Interfaces are a contract between you class and something else. 接口是您的课程与其他课程之间的约定。 You make a commitment to functionality but the contract does NOT implement any logic for your class (to prevent the Transformer.MoveForward" problem). 您对功能做出承诺,但是合同没有为您的类实现任何逻辑(以防止出现Transformer.MoveForward问题)。

Polymorphism in general means that something can appear in different ways. 一般而言,多态意味着某些事物可以以不同的方式出现。 A "Transformer" can be a "Vehicle" and a "Human". “变形金刚”可以是“车辆”和“人类”。 Depending on you language (i use C#) you can implement different behaviours for "MoveForward", depending on the contract you want to fulfil. 根据您的语言(我使用C#),您可以根据要履行的合同为“ MoveForward”实现不同的行为。

Using interfaces instead of a concrete implementation hat several advantages. 使用接口代替具体的实现有几个优点。 First you can switch the implementation without changing the code (Dependency Injection for google lookup ;). 首先,您可以在不更改代码的情况下切换实现(用于Google查找的依赖注入;)。 Second you can easier test you code with testing frameworks and mocking frameworks. 其次,您可以使用测试框架和模拟框架更轻松地测试代码。 Third it is a good practice to use the most generalized interface data exchange (enumerator instad of a list if you only want to interate over the values). 第三,最好使用最通用的接口数据交换(如果只想对值进行求值,则为列表的枚举数instad)。

hope this helps a bit understanding the advantages of interfaces. 希望这有助于对接口的优点有所了解。

The type you use in a local variable declaration (as in your ArrayList example) is not usually that significant. 您在局部变量声明中使用的类型(如ArrayList示例中)通常没有那么重要。 All you have to ensure is that the type of myList (the word to the left of the name 'myList') has to be more specific than the type of any method parameter that takes myList. 您需要确保的是,myList的类型(名称“ myList”左侧的单词)必须比采用myList的任何方法参数的类型更具体。

Consider: 考虑:

ArrayList words = new ArrayList();
sort(words);
removeNames(words);

public void sort(Collection c)  ... blah blah blah

public void removeNames(List words) ...  

I could have replaced the type of 'words' to just be List. 我可以将“单词”的类型替换为List。 It doesn't make any difference to the readability or the behaviour of my program. 它对程序的可读性或行为没有任何影响。 I could not define 'words' to be Object though. 我无法将'words'定义为Object。 That's too general. 太笼统了。

On a related note, when you define a public method, you should give careful consideration about the types of the method's parameters, since this has a direct effect on what the caller can pass in. If I defined sort differently: 与此相关的是,在定义公共方法时, 仔细考虑方法的参数类型,因为这直接影响调用者可以传入的内容。如果我定义的排序不同,则:

ArrayList words = new ArrayList();

// this line will cause a compilation error.
sort(words);

public void sort(LinkedList c)  ... blah blah blah

The definition of sort is now very restrictive. 现在,sort的定义非常严格。 In the first example, the sort method allows any object as the parameter, so long as it implements Collection. 在第一个示例中,sort方法允许任何对象作为参数,只要它实现Collection。 In the second example, sort only allows a LinkedList, it won't accept anything else (ArrayLists, HashSets, TreeSets and many others). 在第二个示例中,sort仅允许一个LinkedList,它将不接受其他任何内容(ArrayList,HashSet,TreeSet和许多其他对象)。 The scenarios in which the sort method can be used are now quite limited. 现在可以使用排序方法的场景非常有限。 This might be for good reason; 这可能是有充分理由的; the implementation of sort may rely on a feature of the LinkedList data structure. 排序的实现可能依赖LinkedList数据结构的功能。 It is only bad to define sort this way if people using this code want a sort algorithm that works for things other than LinkedLists. 如果使用此代码的人们想要一种适用于LinkedLists以外的东西的排序算法,则以这种方式定义排序是很不好的。

One of the main skills in writing java libraries is deciding the types of method parameters. 编写Java库的主要技能之一就是确定方法参数的类型。 How general do you want to be? 您想成为多一般的人?

Collection is a supertype of ArrayList . CollectionArrayList的超类型。 If you only need the functionality provided by Collection , it's good practice because you're explicitly indicating what functionality you need in the variable declaration . 如果只需要Collection提供的功能,那么这是一个好习惯,因为您要在变量声明中明确指出所需的功能。 That you choose an ArrayList in the initialization is irrelevant (though a good default choice); 初始化中选择ArrayList是无关紧要的(尽管是很好的默认选择); the declaration that it's a Collection tells you and any future coder exactly what contract you care about. 它是Collection的声明会告诉您和任何将来的编码人员确切的合同约定。

By declaring and using myList as a Collection, you are hiding the implementation choice you are making (in this case, that it is represented as an ArrayList). 通过声明myList用作Collection,可以隐藏正在做出的实现选择(在这种情况下,它表示为ArrayList)。 In general, this means that any things that depend on your piece of code will only rely on myList behaving as a Collection, not as an ArrayList in particular. 通常,这意味着所有依赖于您的代码的事物都将仅依赖于myList表现为Collection,而不是ArrayList。 That way if you decide to represent it as something else later on (a Set? A Linked List?) for whatever reason, you don't break anything else. 这样,如果您出于某种原因决定以后再将其表示为其他内容(“集合”或“链表”?),则不会破坏其他任何内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM