web-dev-qa-db-ja.com

Java=クラスのインターフェースを推奨する理由は何ですか?

[〜#〜] pmd [〜#〜] は次の違反を報告します:

ArrayList<Object> list = new ArrayList<Object>();

違反は、「「ArrayList」などの実装タイプの使用を避け、代わりにインターフェースを使用する」でした。

次の行は違反を修正します。

List<Object> list = new ArrayList<Object>();

なぜListの代わりにArrayListを使用するのですか?

70
jnancheta

具象型でインターフェースを使用することは、適切なカプセル化とコードの疎結合の鍵となります。

独自のAPIを作成する場合は、この方法に従うことをお勧めします。そうすると、後でユニットテストを(モッキングテクニックを使用して)コードに追加する方が簡単で、将来的に必要に応じて基本となる実装を変更する方が簡単です。

これが 良い記事 です。

それが役に立てば幸い!

76
kolrie

リストの実装からコードを分離するので、これが推奨されます。インターフェースを使用すると、実装(この場合はArrayList)を別のリスト実装に簡単に変更できます。リストで定義されたメソッドのみを使用している限り、コードの残りの部分を変更する必要はありません。

28
AdamC

一般に、インターフェースを実装から分離することは良いことであり、コードの保守が容易になることに同意します。

ただし、考慮しなければならない例外があります。インターフェイスを介してオブジェクトにアクセスすると、間接層が追加され、コードが遅くなります。

興味深いことに、100万長のArrayListへの100億の順次アクセスを生成する実験を実行しました。私の2.4Ghz MacBookでは、Listインターフェイスを介してArrayListにアクセスするのに平均で2.10秒かかりました。タイプがArrayListであると宣言すると、平均で1.67秒かかりました。

大きなリストを処理している場合、内部ループの深部、または頻繁に呼び出される関数の場合は、これを考慮する必要があります。

12
Owen

ArrayListとLinkedListは、項目の順序付けられたコレクションであるリストの2つの実装です。論理的には、ArrayListとLinkedListのどちらを使用するかは問題ではないため、型をそのように制約しないでください。

これは、たとえば、コレクションとリストという異なるものとは対照的です(リストはソートを意味し、コレクションはそうではありません)。

6
SCdF

ArrayListの代わりに後者をListと共に使用する必要があるのはなぜですか?

それは良い習慣です:実装ではなくインターフェイスするプログラム

ArrayListListに置き換えることで、ビジネスユースケースに応じて、以下のようにListの実装を将来変更することができます。

List<Object> list = new  LinkedList<Object>(); 
/* Doubly-linked list implementation of the List and Deque interfaces. 
 Implements all optional list operations, and permits all elements (including null).*/

OR

List<Object> list = new  CopyOnWriteArrayList<Object>(); 
/* A thread-safe variant of ArrayList in which all mutative operations
 (add, set, and so on) are implemented by making a fresh copy of the underlying array.*/

OR

List<Object> list = new  Stack<Object>(); 

/* The Stack class represents a last-in-first-out (LIFO) stack of objects.*/

OR

その他のList固有の実装。

Listインターフェイスはコントラクトを定義し、Listの特定の実装は変更できます。このようにして、インターフェースと実装は疎結合されます。

関連するSEの質問:

「インターフェイスへのプログラム」とはどういう意味ですか?

2
Ravindra babu

クラス/インターフェースのプロパティは、実装に関係なく、使用する動作の規約をクラスに提供するため、インターフェースを通じて公開する必要があります。

しかしながら...

ローカル変数宣言では、これを行うことはほとんど意味がありません。

public void someMethod() {
List theList = new ArrayList();
//do stuff with the list
}

ローカル変数の場合は、型を使用します。それは依然として適切なインターフェースに暗黙的にアップキャスト可能であり、メソッドはその引数のインターフェース型を受け入れると期待されますが、ローカル変数の場合、実装が必要な場合に備えて、実装型をコンテナーとして使用することは完全に理にかなっています。特定の機能。

1
MetroidFan2002

ローカル変数の場合でも、具象クラスでインターフェースを使用すると役立ちます。インターフェースの外にあるメソッドを呼び出すことになる場合があり、必要に応じてリストの実装を変更することは困難です。また、宣言では、最も特定度の低いクラスまたはインターフェイスを使用することをお勧めします。要素の順序が重要でない場合は、リストではなくコレクションを使用します。これにより、コードに最大限の柔軟性がもたらされます。

1
Diastrophism

一般的に、コード行では、インターフェースを気にすることは意味がありません。しかし、APIについて話をしている場合、本当に正当な理由があります。少人数クラス

class Counter {
    static int sizeOf(List<?> items) {
        return items.size();
    }
}

この場合、インターフェースの使用が必要です。自分のカスタムを含めて可能な限り実装のサイズを数えたいので。 class MyList extends AbstractList<String>...

1