blog

Javaの抽象クラスとインターフェース関連の問題と戦うための記事

Javaの抽象クラスとインターフェースの使い方を紹介します。 1.前回述べた抽象クラス:親クラスは子クラスより抽象的で、子クラスは親クラスより具体的です。 上のDogクラスは当然Animalクラスを継...

Aug 12, 2020 · 7 min. read
シェア

この記事では、Javaにおける抽象クラスとインターフェースの使い方を紹介します。

抽象クラス

親クラスは子クラスより抽象的で、子クラスは親クラスより具体的です。

動物や犬の例は「Javaの継承にまつわる問題についての記事」で紹介されています:

public class Animal {
 private String name;
 private int age;
 public Animal(String name, int age) {
 this.name = name;
 this.age = age;
 }
 public Animal() {
 }
 public void say() {
 System.out.println("" + name + ",今年"+ age + "年をとったものだ」)。;
 }
	//getters and setters ...
}
public class Dog extends Animal {
 private String address;
 public Dog(String name, int age, String address) {
 super(name, age);
 this.address = address;
 }
 public Dog() {
 }
 public void say() {
 System.out.println("私の名前は "+ super.getName() + ",今年"+ super.getAge() + "歳、住まいは"+ address + ", ...");
 }
 public void watchDoor() {
 System.out.println("私は、"+ address +" ...");
 }
	//getters and setters ...
}

上のDogクラスは当然Animalクラスを継承しています!しかし、Animalクラスのsay()メソッドについてはよく考えてください。

Animalはとても広い概念で、普段目にする生き物のほとんどは、それを表すコードを書けばクラスを継承することができます。下の図のように:

Animalクラスを継承しているクラスはたくさんありますが、Animalクラスのsay()メソッドはこのような書き方でよいのでしょうか?動物によって話し方が違いますし、動物というのは広い概念ですから、普通はnew Dog()かnew People()になるでしょうが、new Animal()になることはまずありません。

つまり、Animalクラスのsay()メソッド本体はチキン・スクラッチであり、たとえメソッド本体があったとしても、サブクラスによってオーバーライドされてしまうからです。この場合、メソッド本体はまったく必要ありません。

つまり、Animalクラスはより高いレベルに抽象化され、名前や年齢といったあらゆる動物が持つ属性や、発言といったあらゆる動物が持つ行動を持つようになります。

なぜなら、親の行動は「名前はあるが実態はない」からです。サブクラスは「名前」だけを継承すればよく、具体的な「実態」はサブクラスが行います。具体的な「現実」はサブクラスが行います。

このようなAnimalクラスは抽象クラスです。

Dogクラスは変更する必要はありません:

public abstract class Animal {
 private String name;
 private int age;
 public Animal(String name, int age) {//パラメトリック・コンストラクタ
 this.name = name;
 this.age = age;
 }
 public Animal() {//パラメータなしコンストラクタ
 }
 public abstract void say();//抽象メソッド
 
 public String getName() {//具体的に実装されたメソッド
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 
	//getters and setters..
}

抽象クラスの特徴は以下の通りです:

抽象クラスはabstractキーワードで修飾されます。

public abstract class Animal {
 //......
}

メソッド本体を持たないクラスのメソッドは抽象メソッドと呼ばれ、abstract キーワードで変更する必要があります。

public abstract void say();//抽象メソッド

抽象メソッドを持つクラスは抽象クラスでなければなりません。

抽象メソッドを持たないクラスも抽象クラスになります。

抽象クラスは、メンバ変数、コンストラクタ、具体的に実装されたメソッドを持つことができます。コンストラクタを抽象化することはできません。

抽象クラスはインスタンス化できませんが、抽象クラス変数を宣言することができます。

Animal animal = new Animal();// : 'Animal' is abstract; cannot be instantiated
Anima animal;//抽象クラス変数。

Dogクラスのような抽象クラスは、オブジェクトを記述するために使用されますが、抽象クラスのメソッドは具体的に実装されていないため、オブジェクトを記述するのに十分な情報を持っていません。

サブクラスが抽象親クラスを継承するには、2つの方法があります:

  1. サブクラスが抽象クラスでない場合、サブクラスは抽象親クラスの抽象メソッドを実装する必要があります:
public class Dog extends Animal {
	//プロパティ、コンストラクター、その他のメソッド
 
 //抽象親クラスの抽象メソッドを実装する
 @Override
 public void say() {
 System.out.println("私の名前は "+ super.getName() + ",今年"+ super.getAge() + "歳、住まいは"+ address + ", ...");
	}
 
}
  1. サブクラスが抽象クラスの場合、サブクラスは抽象親クラスの抽象メソッドを実装することも、実装しないこともできます。
public abstract class Dog extends Animal {
 //プロパティ、コンストラクター、その他のメソッド
 
 //親クラスの抽象メソッドを実装しないこともできる
}

インターフェイス

インターフェースとは何ですか?

生活の中で、誰もが毎日使うインターフェースのひとつにソケットがあります。

考えてみてください、もしそのようなコードがなかったら、ソケットやプラグはどのように千差万別に製造され、購入したときにどのように機能するでしょうか?ソケットと冷蔵庫を分解し、220Vのコードを手で接続しなければならないでしょう。

言い換えれば、インターフェースとは、両者が遵守する生産仕様/標準、または合意事項であり、両者がそれを遵守する限り、両者は楽しくコミュニケーションし、協力し合うことができます。

Javaの開発では、ソフトウェアシステムは確かに一人で行うのではなく、チームによって行われます。それでは、どのようにAはクラスBを使用することはできません書き込み、BはクラスCを使用することはできませんそれを避けるために、最終的にAがBのコードを変更し、BがCのコードを変更することにつながる?事前に仕様を設定し、誰もがインターフェイスを遵守し、私はあなたのインターフェイスを知っている限り、私はあなたのクラスを呼び出すためにあなたの特定のコードを知る必要はありません。

インターフェイスの使用

インターフェイスに関するいくつかの特徴をマスターすれば、インターフェイスを書くのが楽しくなります:

Javaではintefaceキーワードを使ってインターフェースを宣言します:

public interface Runnable {
}

様々な抽象メソッドは、通常インターフェースに記述されますが、宣言されるだけで、メソッド本体は記述されません。

public interface Runnable {
 /*public abstract*/ void run();
}

メソッドをpublic abstractと宣言する必要はありません。インターフェイスのすべてのメソッドはデフォルトでpublic abstractです。

インターフェイスには、メンバ変数や静的コード・ブロックを置くことはできません。

インターフェイスは定数を含むことができ、デフォルトでは public static final 修飾子となります。

public interface Runnable {
 /*public static final*/ int i = 1;
 void run();
}

クラスは implementations キーワードによってインターフェースを実装し、インターフェースのすべてのメソッドを同時に実装する必要があります。

public class Dog implements Runnable {
 @Override
 public void run() {
 System.out.println("速く走る");
 }
 
 //......
}

インターフェイスを実装したクラスが抽象クラスであれば、インターフェイスのメソッドを実装しなくても使うことができます。

クラスは両方のクラスを継承し、インターフェイスを実装することができます。

public class Dog extends Animal implements Runnable {
 //......
}

クラスは複数のインターフェースを実装できます。

public class Dog implements Runnable, Flyable {
 //......
}

インターフェースは互いに継承することができ、多重継承も可能です。

public interface A {
 //......
}
public interface B extends A, Runnable{
 //......
}

インターフェースはインスタンス化できませんが、インターフェース変数は宣言できます。

Runnable runnable = new Runnable();//'Runnable' is abstract; cannot be instantiated
Runnable runnable;//機能するインターフェイス変数

概要

抽象クラスは abstract キーワードで宣言されます。抽象クラスは、抽象メソッドに加えて、通常のクラスのメンバ変数、コンストラクタ、メソッドを持つことができます。インスタンス化することはできませんが、抽象クラスの変数を宣言することはできます。抽象クラスを継承したサブクラスは、親クラスの抽象メソッドを実装する必要があります。

インターフェイスは interface キーワードで宣言され、抽象メソッドと定数のみを持つことができます。インスタンス化することはできませんが、インターフェイス変数を宣言することはできます。インターフェイスは互いに継承でき、多重継承も可能です。クラスは implementations キーワードを使用してインターフェースを実装し、インターフェースの抽象メソッドを実装する必要があります。

抽象クラスとインターフェースの特徴をまとめると、抽象クラスは「インターフェース」としても使えるようです。抽象クラスがあるのに、なぜインターフェースが必要なのでしょうか?

クラスは単一にしか継承できませんし、抽象クラスが「インターフェイス」として使われる場合、1つのクラスは1つの「インターフェイス」にしか従えないことになり、明らかに実用的ではありません。インターフェースはもっと柔軟です。

Read next

システム・アーキテクチャ設計ノート - 検証と妥当性確認

検証と妥当性確認は、どちらもソフトウェア製品が意図した要件や条件を満たしているかどうかを判断するプロセスです。検証は、分析、設計、コーディング、テスト、レビューなど幅広いプロセスに適用できますが、検証は通常、受け入れプロセスで使用されます。 ソフトウェアプロジェクトの妥当性確認は、一般的に、契約妥当性確認、プロセス妥当性確認、要件妥当性確認、設計妥当性確認、コーディング妥当性確認、統合妥当性確認、文書妥当性確認を含みます。 サプライヤが要件を満たせるかどうか...

Aug 12, 2020 · 2 min read