PMDは、次の違反を報告します。
ArrayList<Object> list = new ArrayList<Object>();
違反は、「'ArrayList' のような実装型を使用しないでください。代わりにインターフェイスを使用してください」でした。
次の行は違反を修正します。
List<Object> list = new ArrayList<Object>();
Listの代わりに後者を使用する必要があるのはなぜArrayListですか?
PMDは、次の違反を報告します。
ArrayList<Object> list = new ArrayList<Object>();
違反は、「'ArrayList' のような実装型を使用しないでください。代わりにインターフェイスを使用してください」でした。
次の行は違反を修正します。
List<Object> list = new ArrayList<Object>();
Listの代わりに後者を使用する必要があるのはなぜArrayListですか?
具象型でインターフェイスを使用することは、適切なカプセル化とコードの疎結合の鍵です。
独自の API を作成するときは、この方法に従うことをお勧めします。そうすれば、(モッキング手法を使用して) コードに単体テストを追加し、将来必要に応じて基になる実装を変更する方が簡単であることが後でわかります。
これについては、良い記事があります。
それが役に立てば幸い!
コードをリストの実装から分離するため、これが推奨されます。インターフェイスを使用すると、実装 (この場合は ArrayList) を別のリスト実装に簡単に変更できます。List で定義されたメソッドのみを使用する限り、残りのコードを変更する必要はありません。
一般に、インターフェイスを実装から分離することは良いことであり、コードの保守が容易になることに同意します。
ただし、考慮しなければならない例外があります。インターフェイスを介してオブジェクトにアクセスすると、間接的なレイヤーが追加され、コードが遅くなります。
興味深いことに、長さ 100 万の ArrayList に対して 100 億回のシーケンシャル アクセスを生成する実験を行いました。私の 2.4Ghz MacBook では、List インターフェイスを介して ArrayList にアクセスするのに平均 2.10 秒かかり、ArrayList 型を宣言すると平均 1.67 秒かかりました。
大きなリスト、内部ループの奥深く、または頻繁に呼び出される関数を使用している場合は、これを考慮する必要があります。
ArrayList と LinkedList は、項目の順序付きコレクションである List の 2 つの実装です。論理的には、ArrayList を使用するか LinkedList を使用するかは問題ではないため、型をそのように制約するべきではありません。
これは、異なるものである Collection と List とは対照的です (List は並べ替えを意味しますが、Collection はそうではありません)。
後者の List を ArrayList の代わりに使用する必要があるのはなぜですか?
それは良い習慣です:実装ではなくインターフェースへのプログラム
に置き換えることArrayListで、ビジネスユースケースに応じて、将来的に以下のように実装をList変更できます。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).*/
また
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.*/
また
List<Object> list = new Stack<Object>();
/* The Stack class represents a last-in-first-out (LIFO) stack of objects.*/
また
他のList特定の実装。
Listインターフェイスはコントラクトを定義し、特定の実装をList変更できます。このように、インターフェースと実装は疎結合です。
関連する SE の質問:
一般に、コード行では、インターフェイスを気にすることは意味がありません。しかし、API について話しているのであれば、それには十分な理由があります。少人数クラスになりました
class Counter {
static int sizeOf(List<?> items) {
return items.size();
}
}
この場合、インターフェースの使用が必要です。自分のカスタムを含め、可能なすべての実装のサイズを数えたいからです。class MyList extends AbstractList<String>....
クラス/インターフェイスのプロパティは、実装に関係なく、使用する動作の契約をクラスに与えるため、インターフェイスを介して公開する必要があります。
でも...
ローカル変数宣言では、これを行うのはほとんど意味がありません:
public void someMethod() {
List theList = new ArrayList();
//do stuff with the list
}
ローカル変数の場合は、型を使用してください。適切なインターフェイスに暗黙的にアップキャスト可能であり、メソッドはその引数のインターフェイス タイプを受け入れる必要がありますが、ローカル変数の場合、実装が必要な場合に備えて、実装タイプをコンテナーとして使用することは完全に理にかなっています-特定の機能。
ローカル変数の場合でも、具体的なクラスでインターフェイスを使用すると役立ちます。インターフェイスの外側にあるメソッドを呼び出すことになり、必要に応じて List の実装を変更することが困難になる場合があります。また、宣言では、特定性が最も低いクラスまたはインターフェイスを使用することをお勧めします。要素の順序が重要でない場合は、List の代わりに Collection を使用します。これにより、コードに最大限の柔軟性がもたらされます。