インターフェイス
多重継承とインターフェイス
Java言語のオブジェクト指向、及びポリモーフィズムでは「インターフェイス」という技術が非常に重要です
Java言語のインターフェイスは「多重継承」をサポートするものです
これまで、あるクラスを継承しサブクラスとして拡張することができました
しかし、二つ以上のクラスをひとつのサブクラスに拡張することはできません
ひとつのサブクラスが二つのスーパークラスを拡張することを多重継承といいます
これはC++の技術で、Java言語は多重継承ができないのです
多重継承では、様々な実装の問題があります
最初にあげられるのが、名前の重複です
二つのスーパークラスに同じシグネチャのメソッドなのが存在する場合、曖昧になってしまいます
さらに、その二つのスーパークラスが同じひとつのクラスを拡張していたのならば……
C++では、この問題をvirtualなどで解決しています
Java言語では、先ほども言ったとおり多重継承はできません
サブクラスのスーパークラスは必ずひとつしかありません
そこで、クラスにメソッドを多重継承する役割を持つのがインターフェイスなのです
インターフェイスは抽象クラスによく似ているといわれます
なぜならば、インターフェイスには実装は無く宣言だけが存在するからです
インターフェイスは、いわばメソッドの宣言をする場所なのです
インターフェイスの宣言は次のような書式になります
interface intfName {
type metName(Param);
...
}
intfNameにはインターフェイス名です。metNameはメソッド名、Paramはパラメータを宣言します
interfaceの前に、アクセス権を指定する修飾子 public を指定することもできます
アクセス権とその修飾子については、後ほど詳しくお話します
この場ではpublicはどこからでも呼び出せるインタフェイスであることを表すと覚えてください
メソッドでもアクセス権限の修飾子の指定は可能です
デフォルトでインターフェイスメソッドはpublic abstractです
これが、インターフェイスメソッドの役割なので、通常は修飾子を指定することはありません
ただし、インターフェイスメソッドを実装するときに public であることを意識する必要があります
これだけでは、メソッドの宣言だけなので抽象クラスにそっくりですね
問題はどうインターフェイスの宣言を実装するかです
インターフェイスで宣言されたメソッドを定義するには、クラスにインターフェイスを実装する必要があります
クラスにインターフェイスを実装するには inpliments キーワードを使用します
class clsName implements intfName1 , intfName2...
clsNameは、定義するクラス名です
intfName1 , intfName2...は実装するインターフェイスの指定をします
ここで指定されるインターフェイスは、当然複数指定することができます
classの前に修飾子を指定したり、clsName の後に extends キーワードでスーパークラスを拡張しても良いです
public class clsName extends super_class implements intfName1 , ...
重要なのは、クラスにインターフェイスが実装された場合
インターフェイスで宣言されているメソッドを必ず全て定義しなければならないことです
定義しなかった場合、コンパイルすることができません
interface intf {
void write(String str);
}
class LOVE_HINA implements intf {
public void write(String str) {
System.out.println(str);
}
}
class test {
public static void main(String args[]) {
LOVE_HINA obj = new LOVE_HINA();
obj.write("祝福のときは来る、手を伸ばして");
}
}
クラスは複数のインターフェイスを実装することができます
とうぜん、extendsで同時に他のクラスを拡張することも可能です
次のプログラムでは、super_classを拡張し、さらにインターフェイスを実装しています
interface intf1 {
void write(String str);
}
interface intf2 {
void hina(String name , int age);
}
class super_class {
String name;
int age;
}
class LOVE_HINA extends super_class implements intf1 , intf2 {
public void write(String str) {
System.out.println(str);
}
public void hina(String name , int age) {
this.name = name;
this.age = age;
System.out.println(this.name + "\t" + this.age);
}
}
class test {
public static void main(String args[]) {
LOVE_HINA obj = new LOVE_HINA();
obj.write("名前\t\t年齢");
obj.hina("前原しのぶ" , 13);
}
}
interfaceには、もう一つの使い方があります
interfaceではメソッド以外に、変数を定数として宣言することもできます
なぜならば、インターフェイスで宣言された変数はデフォルトでpublic static finalなのです
これは設計とは異なる使い方のようですが、便利なプログラムテクニックとされています
呼び出しには、次のようにアクセスします
intfName.var;
intfNameはインターフェイス名を、varには変数名を指定します
普通は、インターフェイスの変数に修飾子は指定されません
インターフェイスでの変数の宣言方法は、これまでのメンバ変数の宣言と同じです
何も修飾子を指定しなくても、public static final であることを忘れないでください
Javaでは、一連の関連する定数郡をインターフェイスでまとめて宣言することができるのです
interface NARU {
String name = "成瀬川なる";
int age = 17;
char blood_type = 'A';
void write();
}
class LOVE_HINA implements NARU{
String name = NARU.name;
int age = NARU.age;
public void write() {
System.out.print(this.name + "\t" + this.age);
}
}
class test {
public static void main(String args[]) {
LOVE_HINA naru = new LOVE_HINA();
System.out.println("名前\t\t年齢\t血液型");
naru.write();
System.out.println("\t" + NARU.blood_type);
}
}
インターフェイスの定数は、publicでstaticなので、implementの必要はありません
インターフェイスの継承
さらに、インターフェイスはextendsキーワードを使用して拡張することができます
インターフェイスの継承は、クラスの継承と異なり多重継承が可能です
これは、インターフェイスが宣言に専念したため可能になったことです
インターフェイスも、拡張されたインターフェイスのことをスーパーインターフェイスと呼びます
異なる複数のスーパーインターフェイスに同名の変数が存在した場合コンパイルエラーが発生します
メソッドに関しては、実装がないので同じ構文のメソッドが存在してもかまいませんが
戻り値の型が同一でなくてはいけません
異なっていた場合はやはりエラーになります
インターフェイスの継承は、次のように記述します
interface intfName extends sprIntf1 , sprIntfN... {
}
intfNameにはインターフェイス名を指定します
sprIntfには、スーパーインターフェイスを指定します
sprIntfは複数のインターフェイスを指定することができます
その場合は、各インターフェイス名をカンマ「 , 」で区切ります
interface A {
void write(String str , int synchro);
}
interface B {
String third = "逃げちゃだめだ";
}
interface C extends A , B {
void write(String str);
}
class EVA implements C {
public void write(String str , int synchro) {
System.out.println(str);
System.out.println("シンクロ率 : " + synchro + "%");
}
public void write(String str) {
for (int count = 0 ; count <= 5 ; count++)
System.out.println(str);
}
}
class test {
public static void main(String args[]) {
EVA ev = new EVA();
ev.write("初号機、完全に沈黙!パイロットの反応がありません" , 23);
ev.write(ev.third);
}
}
インターフェイスCは、スーパーインターフェイスA , Bを拡張しています
つまり、インターフェイスCは A , B の宣言を引き継いでいることになります
これをクラスEVAでインプリメントしているので、main()メソッドの動作は正常に行われます
interface
インターフェイスの宣言をします
インターフェイスは他のインターフェイスをinplementsすることはできません
インターフェイスは、クラスで実装するメソッドの宣言を行います
また、インターフェイスで定義された変数は、定数として扱うことができます
インターフェイスのメソッドはfinalやstatic修飾子は使用できません
implements
クラスの宣言時に使用します
ひとつ、または複数のインターフェイスをインプリメントします
複数のインターフェイスをインプリメントする場合、各インターフェイスをカンマ「 , 」で区切ります
必ず extends clsName によるクラスの継承よりも後に指定します