为什么要将对象分配给接口?
我曾多次听说过在实例化对象时你应该这样做:
“Interface”name = new“Class”();
例如,对于实现List
的类链表:
List name = new LinkedList();
LinkedList
实现了许多接口,包括queue,deque等。上面的代码和之间有什么区别
LinkedList name = new LinkedList();
要么
Queue name = new LinkedList();
为什么必须两次指定类型; 这似乎是多余的,但oracledocs似乎并未提及它。
LinkedList
在Java 7中是多余的。它可以重写为LinkedList
。
你想写类似的东西的原因:
// Java 7 way: List name = new LinkedList<>();
如果您改变主意,将为您提供更改数据收集的自由。 您的代码以这种方式更加灵活。 您应该注意的是,您可以使用的方法仅限于左侧类型(在本例中为List
)。 这意味着如果您使用层次结构中较高的类型( Object
是极端示例),您可能无法获得所需的所有function。
LinkedList name = new LinkedList<>();
将公开LinkedList
及其超类中定义的方法。
Queue name = new LinkedList<>();
将公开Queue
中定义的方法及其扩展的接口。
您应该将对象定义为一个类/接口,它包含您需要的所有内容(方法,变量等),同时使其尽可能抽象。
例如,这隐藏了实现细节并允许在实现之间更容易地切换。
请注意,由于菱形运算符,您不必在初始化中指定类型。
首先,Interface是一种抽象类型,用于指定类必须实现的内容。 实现接口的任何类都必须通过实现其方法来满足其合同,并且属于该类型。因此,通过实现List接口,LinkList是一种列表。
通过编码到接口而不是具体类,您的代码变得更松散耦合。 这意味着您的代码不是绑定到LinkList而是绑定到List接口,并且可以随时更改为实现列表接口的任何内容。 因此,如果出于某种原因,LinkList不再满足您的要求并且您需要,那么让我们说一个ArrayList,因为它也实现了List接口,您只需更改为:
List name = new ArrayList ();
并且所有其他编程逻辑将保持不变,因为两个类具有相同的方法,因为它们实现相同的接口。
这并不像看起来那么简单。 如果您使用:
List name = new LinkedList ();
如果你想从链接列表切换到arraylists,那么维护就更少了。
关于冗余, List name = new LinkedList()
声明List
类型的name
并调用LinkedList
构造函数。 你可以这样:
List name = someRandomObject.someRandomHelperMethod();
这个辅助方法“刚刚发生”以返回一个列表,因此没有冗余。
使用Java 7,可以跳过明显冗余的通用args:
List someL = new ArrayList<>();
而不是
List someL = new ArrayList ();
如果您对接口进行编码,则可以轻松地轻松切换实现。 如果ArrayList比LinkedList更适合您的需求,那么您只能更改一行。 如果您需要LinkedList类(或任何其他子类型)中的特定方法,那么它是完全有效的
LinkedList name = new LinkedList ()
至于冗余,如果您指的是generics类型声明,那么我建议您查看Guava库。 这些有一些很好的静态导入方法来删除它。 例如, 对于ArrayList ,它将是
List name = newArrayList()
代替
List name = new ArrayList ()
LinkedList也有类似的方法。
在Java 7中还有钻石操作符,但这仍然比Guava的静态导入更冗长。
上面的代码和之间有什么区别
LinkedList
name = new LinkedList (); 要么
Queue
name = new LinkedList ();
有几个关键的区别。
使用List
接口和使用LinkedList
对象之间的区别在于我定义了与实现对象的交互以遵守List
接口。 最终,我不关心实现是什么*,只要它表现得像某种List
。
如果我使用具体的LinkedList
对象,那么我不仅要关心类型是什么,而且我可以使用比我应该更多的东西 – 因为它也实现了Queue
接口,我可以对它进行类似队列的操作,可能适合也可能不适合。
最终,您的代码应该是SOLID ; 在这里,我们遵循依赖性倒置原则 ,它允许我们依赖于接口而不是具体的实现。 它允许我们根据需要为ArrayList
替换LinkedList
。
*:当然,出于性能原因,您应该关注底层实现。 但是,你可能还不在乎。