与具体类的接口

时间:2016-06-24 07:02:12

标签: java design-patterns arraylist collections interface

如果我们考虑下面的两个实现,那么第一个实际使用的是什么?

List<String> a= new ArrayList<String>();
ArrayList<String> b= new ArrayList<String>();

根据我在帖子中看到的内容,第一个实现有助于避免破坏更改,就像我们可以再次更改实现一样

a=new TreeList<String>();

但是我不明白为什么我们只能使用List接口方法来实际使用更改treelist的实现?

4 个答案:

答案 0 :(得分:2)

  

但是我不明白为什么我们只能使用List接口方法来实际使用更改treelist的实现?

接口List的不同实现对于不同的操作具有不同的性能特征。您应该选择哪种List实现不是任意的 - 不同的实现对于不同的目的更有效。

例如,在ArrayList上将元素插入中间的位置是昂贵的,但LinkedList上的元素很便宜,因为实现的工作方式。同样,通过索引访问元素在ArrayList上很便宜,但在LinkedList上却很贵。

当您开始编写程序时,您可能会使用ArrayList而不考虑太多,但稍后您会发现LinkedList会更有效。

当你针对界面List进行编程而不是特定的实现时,很容易从ArrayList更改为LinkedList - 到程序的其余部分,它仍然看起来就像List一样,所以你只需改变一行。

答案 1 :(得分:1)

TreeList不存在,因此我们以PersistentList为例。

假设您有一个@Entity要保存到数据库:

public class MyMagicEntity {
    @OneToMany
    List<MyChildEntity> children;

    public void setChildren(final List<MyChildEntity> children) {
        this.children = children;
    }
}

现在,当您创建MyMagicEntity时,您会执行类似

的操作
final MyMagicEntity mme = new MyMagicEntity();
final List<MyChildEntity> children = new ArrayList<>();
children.add(new MyChildEntity("one"));
children.add(new MyChildEntity("two"));
children.add(new MyChildEntity("three"));
mme.setChildren(children);

//save to DB

因此,您创建了一个ArrayList,并将其传递到MyMagicEntity,并将其分配给List - 它并不关心底层实现是否只要它是List {1}}。

现在,稍后你会这样做:

final MyMagicEntity mme = //load from DB
final List<Children> children = mme.getChildren();

那么,children是什么?好吧,如果我们使用JPA和Hibernate,它实际上是PersistentList,而不是ArrayList

当我们访问children的成员时,Hibernate将从数据库中取出它们。此List仍然是List - 您的程序不必知道任何此类内容。

您可以在不使用List界面的情况下执行此操作吗?没有!这是因为:

  • 您无法创建PersistentList
  • Hibernate无法创建ArrayList

虽然这是一个极端的例子,List的基本行为完全不同,但这适用于各种其他情况。

例如:

  • ArrayListLinkedList具有不同的性能特征,您可能需要切换
  • Guava有ImmutableList您可能想要使用
  • Collections.unmodifyableListimplements List,您可能想要使用
  • 您可以想象一个List由文件支持

基本思想是List定义任何列表必须能够执行的操作,而不是如何完成。

答案 2 :(得分:1)

让我们假设你已经决定开发一个更有效的List实现。也许内部具有更好的内存管理,或者可能是更快的设置方法(插入)实现。您可以实现List接口,其余代码将继续工作而不做任何更改,除了这一行。您还可以扩展ArrayList并编写自己的代码。

//Old code
List<String> a = new ArrayList<String>();
a.set(0, "Test");

//New code
List<String> a = new MyCustomisedList<String>();
//Same code, but your optimized set logic. May be faster...
a.set(0, "Test");

答案 3 :(得分:0)

此处List是一个接口,其中包含可以使用List执行的所有常用操作方法。

List接口是ArrayListLinkedList的父级,还有更多类。因此,它可以保存所有这些类型的Object引用。

所有这些List方法都有不同的(或自己的类型)实现与不同的类。因此,无论您使用何种方法,都会根据属于该类的Object的覆盖方法定义自动应用。

List<String> a= new ArrayList<String>();
ArrayList<String> b= new ArrayList<String>();

现在,在你的情况下,你可以声明两种方式都没问题。但是假设像这样的情景。

您正在调用某些服务,并且您知道返回任何List类型(非特定)的Object。它可能是LinkedListArrayList或任何其他类型的列表。

当时您得到的任何回复您可以轻松地将这些回复保存在List参考变量类型中。

收集结果后,您可以进一步区分对象类型。