たとえば、次のクラスを見てください。
public class Tmp {
public static void main(String[] args) {
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(1);
}
}
コンパイルすると次のようになります。
Compiled from "Tmp.java"
public class Tmp extends java.lang.Object{
public Tmp();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2; //class java/util/ArrayList
3: dup
4: invokespecial #3; //Method java/util/ArrayList."<init>":()V
7: astore_1
8: aload_1
9: iconst_1
10: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
13: invokevirtual #5; //Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
16: pop
17: return
}
このクラスの間:
public class Tmp {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<Integer>();
numbers.add(1);
}
}
これにコンパイルされます:
Compiled from "Tmp.java"
public class Tmp extends java.lang.Object{
public Tmp();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2; //class java/util/ArrayList
3: dup
4: invokespecial #3; //Method java/util/ArrayList."<init>":()V
7: astore_1
8: aload_1
9: iconst_1
10: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
13: invokeinterface #5, 2; //InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
18: pop
19: return
}
唯一の違いは、最初のもの ( を使用ArrayList
) が呼び出しをinvokevirtual
行い、もう 1 つは (使用をList
使用)であることがわかりますinvokeinterface
。 実際には(この男によると〜38% )invokeinterface
よりも髪の毛が遅いです。これは明らかに、具象クラスの仮想メソッド テーブルとインターフェイスのメソッド テーブルを検索するときに JVM が実行できる最適化によるものです。だからあなたの言ってることは本当です。インターフェイスの呼び出しは、具体的なクラスの呼び出しよりも遅くなります。invokevirtual
ただし、私たちが話している速度の種類を考慮する必要があります。1 億回の呼び出しでは、実際の差は 0.03 秒でした。したがって、実際に速度を大幅に低下させるには、大量の呼び出しが必要です。
一方、@ChinBoon が指摘しているように、特にコードが何らかの sort を返す場合は、インターフェイスにコーディングすると、コードを使用する人にとって非常に簡単になりますList
。そのため、ほとんどの場合、コーディングの容易さは相対的なパフォーマンスの犠牲をはるかに上回ります。
@MattQuigley のコメントを読み、家に帰るドライブで考えた後に追加
これが意味することは、これはあまり心配する必要がないということです。パフォーマンスの向上またはペナルティは、非常に小さい可能性があります。
戻り値の型とメソッドのパラメーターにインターフェイスを使用することは、非常に良いアイデアです。これにより、あなたとあなたのコードを使用するすべての人がList
、ニーズに最適な の実装を使用できます。List
私の例では、99% の確率で を返すメソッドを使用した場合、パフォーマンスを向上させるためだけにそれを具象クラスにキャストするのは得策ではないことも示しています。キャストにかかる時間は、パフォーマンスの向上を上回る可能性があります。
そうは言っても、この例は、ローカル変数の場合、インターフェースよりも具象クラスを使用する方が実際に優れていることも示しています。使用するメソッドが onList
のメソッドだけである場合、副作用なしで実装クラスを切り替えることができます。さらに、必要に応じて実装固有のメソッドにアクセスできます。さらに、マイナーなパフォーマンスの向上があります。
tl;dr
メソッドの戻り値の型とパラメーターには常にインターフェイスを使用します。ローカル変数に具象クラスを使用することをお勧めします。わずかなパフォーマンスの向上が得られ、使用するメソッドがインターフェイス上にある場合のみ実装を切り替えるコストはありません。結局、あまり気にしなくていいです。(戻り値の型とパラメーターのことを除いて。それは重要です。)