为什么我们在实例化它们之前首先将子类型声明为它们的超类型?

chr*_*ode 21 java oop

阅读其他人的代码,我见过很多:

List<E> ints = new ArrayList<E>();
Map<K, V> map = new HashMap<K, V>();
Run Code Online (Sandbox Code Playgroud)

我的问题是:以这种方式实例化它们的意义/优势是什么,而不是:

ArrayList<E> ints = new ArrayList<E>();
HashMap<K, V> map = new HashMap<K, V>();
Run Code Online (Sandbox Code Playgroud)

令人感到奇怪的是,我从未见过如下:

CharSequence s = new String("String");
Run Code Online (Sandbox Code Playgroud)

要么

OutputStream out = new PrintStream(OutputStream);
Run Code Online (Sandbox Code Playgroud)


重复(问题的第一部分):

何时/为何使用/定义接口

在java中使用接口或类型进行变量定义?

我什么时候应该在java中使用接口?

为什么要为每个类创建接口而不是它们的实现

这两个java变量声明有什么区别?

Per*_*ion 24

快速回答?使用接口和超类可以提高代码的可移植性和可维护性,主要是隐藏实现细节.采用以下假设示例:

class Account {
    private Collection<Transaction> transactions;

    public Account() {
        super();
        transactions = new ArrayList<Transaction>(4);
    }

    public Collection<Transaction> getTransactions() {
        return transactions;
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经宣布了一个帐户合同,该合同规定发布到帐户的交易可以作为集合检索.我的代码的调用者不必关心我的方法实际返回什么样的集合,也不应该.如果需要的话,这可以让我更改内部实现,而不会影响(也就是打破)未知数量的客户端.因此,如果我发现我需要在我的事务中强加某种唯一性,我可以将上面显示的实现从ArrayList更改为HashSet,而不会对使用我的类的任何人产生负面影响.

public Account() {
    super();
    transactions = new HashSet<Transaction>(4);
}
Run Code Online (Sandbox Code Playgroud)

至于你的第二个问题,我可以说你在任何有意义的地方都使用了可移植性和封装的原则.在那里没有可怕的CharSequence实现,而String是迄今为止最常用的.所以你不会看到很多开发人员在他们的代码中声明CharSequence变量.


Ros*_*atl 11

使用接口的主要优点是,您可以稍后更改实现(类),而无需更改多于创建实例的单行并执行分配.


Bhu*_*han 7

对于

List<E> ints = new ArrayList<E>();
Map<K, V> map = new HashMap<K, V>();
Run Code Online (Sandbox Code Playgroud)

List并且Map是接口,因此可以将实现这些接口的任何类分配给这些引用.

ArrayListLinkedList实现List接口的几个类之一(另一个是).

与...相同Map.HashMap,LinkedHashMap,TreeMap都实现地图.

这是一个通用原则来编程接口而不是实现.因此,编程任务变得更容易.您可以动态更改引用的行为.

如果你写

ArrayList<E> ints = new ArrayList<E>();
HashMap<K, V> map = new HashMap<K, V>();
Run Code Online (Sandbox Code Playgroud)

ints并且mapArrayListHashMap只有永远.


Osc*_*Ryz 5

是一种设计原则,您对接口进行编程而不是对实现进行编程

这样,您可以稍后为同一接口提供新的实现。

从上面的链接 Eric Gamma 解释说:

这个原则实际上是关于必须在大型应用程序中仔细管理的依赖关系。添加对类的依赖很容易。这几乎太容易了;只需添加一个导入语句,Eclipse 等现代 Java 开发工具甚至会为您编写此语句。有趣的是,反过来并不那么容易,摆脱不需要的依赖可能是真正的重构工作,甚至更糟的是,阻止您在另一个上下文中重用代码。因此,在引入依赖项时,您必须睁大眼睛进行开发。这个原则告诉我们,依赖一个接口往往是有益的。

在这里,术语interface不仅指 Java 工件,还指给定对象具有的公共接口,它基本上由它拥有的方法组成,因此,它可以是 Java 接口(例如List您的示例中所示)或具体的超类。

因此,在您的示例中,如果您想使用 aLinkedList代替它会更难,因为该类型已经声明为ArrayList仅 list 就足够了。

当然,如果您需要来自给定实现的特定方法,则必须将其声明为该类型。

我希望这有帮助。