出典: InfoWorld 今日は、開発者がどのような場合に抽象クラスを使用し、どのような場合にインターフェイスを使用する必要があるかを学びます。また、Java 言語のこれらの要素の違いと、それらをプログラムで使用する方法についても説明します。 抽象クラスと抽象インターフェイスは、Java コードだけでなく、Java Development Kit (JDK) 自体でも非常に一般的です。これらの要素はそれぞれ、異なる目的を果たします。
- インターフェイスは、抽象メソッドと静的定数の実装に役立つ Java 言語の構造です。
- 抽象クラスは通常のクラスと似ていますが、抽象メソッド、つまり本体のないメソッドを含めることができる点が異なります。抽象クラスは作成できません。
インターフェースとは
本質的に、インターフェイスはコントラクトであるため、その作成の目的を定義するのは実装に依存します。インターフェイスは可変インスタンス変数を使用できず、最終変数のみを使用できます。インターフェースを使用する場合
インターフェイスは、コードを分離し、ポリモーフィズムを実装するのに非常に役立ちます。JDK のListインターフェースでこれを確認できます。public interface List<E> extends Collection<E> {
int size();
boolean isEmpty();
boolean add(E e);
E remove(int index);
void clear();
}
お気づきかと思いますが、このコードは短いですが、非常に説明的です。具象クラスを使用してインターフェイスにメソッドを実装するために使用されるメソッド シグネチャを簡単に確認できます。Listインターフェイスには、ArrayList、Vector、LinkedList、およびその他のクラスによって実装できるコントラクトが含まれています。ポリモーフィズムを使用するには、 Listを使用して変数の型を宣言し、利用可能なインスタンスのいずれかを選択するだけです。別の例を次に示します。
List list = new ArrayList();
System.out.println(list.getClass());
List list = new LinkedList();
System.out.println(list.getClass());
出力は次のとおりです。
クラス java.util.ArrayList クラス java.util.LinkedList
この場合、 ArrayList、LinkedList 、およびVector の実装メソッドが異なります。これは、インターフェイスを使用するための優れたシナリオです。多くのクラスが同じメソッド アクションを持つ親クラスに属していることに気付いた場合は、動作が異なります。このような状況では、インターフェイスを使用することをお勧めします。次に、インターフェイスを使用するためのいくつかのオプションを見てみましょう。
インターフェイスメソッドのオーバーライド
すでにご存知のとおり、インターフェイスは、具体的なクラスによって実装される必要がある一種のコントラクトです。インターフェイス メソッドは暗黙的に抽象的であり、クラスの具体的な実装が必要です。以下に例を示します。public class OverridingDemo {
public static void main(String[] args) {
Challenger challenger = new JavaChallenger();
challenger.doChallenge();
}
}
interface Challenger {
void doChallenge();
}
class JavaChallenger implements Challenger {
@Override
public void doChallenge() {
System.out.println("Challenge done!");
}
}
結論:
チャレンジ完了!
インターフェイス メソッドは暗黙的に抽象であることに注意してください。これは、それらを明示的に抽象として宣言する必要がないことを意味します。
定数変数
覚えておくべきもう 1 つのルールは、インターフェイスには定数変数のみを含めることができるということです。以下に例を示します。public class Challenger {
int number = 7;
String name = "Java Challenger";
}
ここで、両方の変数は暗黙的なFinal 変数とstatic 変数です。これは、インスタンスから独立した定数であり、変更できないことを意味します。ここで、 Challengerインターフェースの変数を変更してみます。次のようにしましょう。
Challenger.number = 8;
Challenger.name = "Another Challenger";
これによりコンパイル エラーが発生します。
最終変数 'number' に値を代入できません 最終変数 'name' に値を代入できません
デフォルトのメソッド
Java 8 でデフォルトのメソッドが導入されたとき、一部の開発者はそれらが抽象クラスと同じになるだろうと考えていました。ただし、インターフェイスは状態を持つことができないため、これは当てはまりません。デフォルト メソッドには実装がある場合がありますが、抽象メソッドには実装がありません。デフォルトのメソッドはラムダ式とストリームによる革新の結果ですが、慎重に使用する必要があります。デフォルトのメソッドを使用する JDK のメソッドは、 Iterableインターフェースの一部であるforEach()です。コードを各Iterable実装にコピーする代わりに、単純にforEachメソッドを再利用できます。default void forEach(Consumer<? super T> action) {
// Code implementation here...
Iterable実装では、新しいメソッド実装を必要とせずにforEach ()メソッドを使用できます。その後、デフォルトの方法でコードを再利用できます。独自のデフォルトメソッドを作成してみましょう。
public class DefaultMethodExample {
public static void main(String[] args) {
Challenger challenger = new JavaChallenger();
challenger.doChallenge();
}
}
class JavaChallenger implements Challenger { }
interface Challenger {
default void doChallenge() {
System.out.println("Challenger doing a challenge!");
}
}
結果:
挑戦するチャレンジャー!
デフォルトのメソッドに関しては、そのような各メソッドを実装する必要があることに注意することが重要です。デフォルトのメソッドを静的にすることはできません。次に、抽象クラスに移りましょう。
抽象クラスの本質
抽象クラスはインスタンス変数を使用して状態を持つことができます。これは、インスタンス変数を使用および変更できることを意味します。以下に例を示します。public abstract class AbstractClassMutation {
private String name = "challenger";
public static void main(String[] args) {
AbstractClassMutation abstractClassMutation = new AbstractClassImpl();
abstractClassMutation.name = "mutated challenger";
System.out.println(abstractClassMutation.name);
}
}
class AbstractClassImpl extends AbstractClassMutation { }
結論:
突然変異した挑戦者
抽象クラス内の抽象メソッド
インターフェイスと同様、抽象クラスは抽象メソッドを持つことができます。抽象メソッドは本体のないメソッドです。インターフェイスとは異なり、抽象クラスの抽象メソッドは明示的に抽象として宣言する必要があります。以下に例を示します。public abstract class AbstractMethods {
abstract void doSomething();
}
ここでは、実装も抽象 キーワードも使用せずにメソッドを宣言しようとしています。
public abstract class AbstractMethods {
void doSomethingElse();
}
残念ながら、コンパイル エラーが発生します。
メソッド本体が欠落しているか、抽象宣言が行われています
抽象クラスを使用する場合
可変状態を実装する必要がある場合は、抽象クラスをお勧めします。たとえば、Java Collections Framework には、変数の状態を使用するAbstractListクラスが含まれています。クラスの状態を維持する必要がない場合は、通常、インターフェイスを使用する方が適切です。抽象クラスとインターフェイスの違い
オブジェクト指向プログラミングの観点から見ると、インターフェイスと抽象クラスの主な違いは、インターフェイスは状態を持つことができないのに対し、抽象クラスはインスタンス変数を含む状態を持つことができることです。もう 1 つの重要な違いは、クラスは複数のインターフェイスを実装できるが、拡張できるのは 1 つの抽象クラスのみであることです。このソリューションは、多重継承 (複数のクラスの拡張) がコードのデッドロックを引き起こす可能性があるという事実に基づいています。Java 言語の開発者は、これを避けることにしました。もう 1 つの違いは、インターフェイスはクラスによって実装することも、インターフェイスによって拡張することもできますが、クラスは拡張することしかできないことです。ラムダ式は関数型インターフェイス (つまり、メソッドが 1 つだけあるインターフェイス) でのみ使用できるのに対し、抽象メソッドが 1 つだけある抽象クラスではラムダ式を使用できないことに注意することが重要です。抽象クラスとインターフェイスの違いをさらにいくつか示します。 インターフェース:- Final 静的変数のみを持つことができます。インターフェイスはそれ自体の状態を変更することはできません。
- クラスは複数のインターフェイスを実装できます。
- implements キーワードを使用して実装できます。インターフェイスは別のインターフェイスを拡張できます。
- メソッドでは、静的な最終フィールド、パラメーター、またはローカル変数のみを使用できます。
- Java では関数型インターフェイスのみがラムダ関数を使用できます。
- コンストラクターを持つことはできません。
- 抽象メソッドが含まれる場合があります。
- デフォルトメソッドと静的メソッドを使用できます (Java 8 で導入)。
- 実装されたプライベート メソッドを持つことができます (Java 9 で導入)。
- 任意のインスタンス変数または静的変数、可変または不変を含めることができます。
- クラスは 1 つの抽象クラスのみを拡張できます。
- 変更可能なフィールド、パラメータ、またはローカル変数のインスタンスが含まれる場合があります。
- 抽象メソッドが 1 つだけある抽象クラスでは、ラムダ式を使用できません。
- コンストラクターがある場合があります。
- 任意のメソッドを使用できます。
GO TO FULL VERSION