2015年10月16日金曜日

implementsとはなにか。

implementsとはなんでしょうか。似たようなものにextendsがありますね。extendsはクラスを継承し、スーパークラスのメソッドを用いるためのものでした。implementsも似たようなもので、簡単にいえば親のメソッドの継承をするという大体同じ働きをするわけですが、implementsはクラスの継承ではなくインターフェイス(interface)の継承に対応するものです。

大体同じ働きをするなら、なんで2つは分かれているんでしょうか。それは「プログラマーのミスを防止するため」です。

コードを書きながら説明してみる

実際にコードを書きながら説明してみましょう。まずは抽象メソッドというものから説明します。
例えば、製品の名前を表示するdispNameというメソッドを考えます。

class base{
  public void dispName(){
    System.out.println("それぞれのクラスで再定義してね。"); //特になにもしない
  }

このbaseクラスのdispNameは特になにもしていません。なぜなら、dispNameはそれぞれの製品の名前を表示するメソッドなので、あらかじめ一つの決まった処理を書いておくわけにいかないからです。それぞれの製品は個別の名前を持っており、そのため、個別のクラスで別々の処理が必要になるからです。

例えば次のサブクラスみたいな感じです。

class seihinA extends base{
  public void dispName(){
    System.out.println("製品Aです");
  }
}

seihinAクラスはbaseクラスを継承してdispNameを「製品Aです」を表示するメソッドに再定義していますね。このような再定義は「オーバーライド」と呼ばれます。(似たようなものにオーバーロードがありますが、これは多重定義のことで違うものです。注意。)

なんでこんな何もしないメソッドをあらかじめ用意して個別のクラスで再定義して使っているかというと、それぞれのクラスで同じ働きのメソッド(製品の名前を表示する)に適当なメソッド名を使われると困るからです。

例えば「製品の名前を表示する」という機能は全く同じなのにshowNameとかdispNameとかnameSeihinとかproductNameとか何種類も名前があったら混乱しますね。特に大規模なプロジェクトで大人数でコードを書くとき、このようなメソッド名の混乱は致命的です。ていうかちゃんと動かなくなります。

そのため、特になにもしないメソッドを最初にあらかじめ定義し、これをそれぞれのサブクラスが使いまわすわけです。するとメソッド名の混乱はなくなりますね。このような特に何もしないメソッドは抽象メソッドと呼ばれます。抽象メソッドは次のように書きます。

abstract class base{
  abstract public void dispName();
  }
}

赤で示されているように、abstractを先頭につけます。また、こういう抽象メソッドを含むクラスを抽象クラスといいます。(なお、抽象クラスは抽象メソッドを「含む」クラスであって、抽象メソッドだけを持つクラスではありません。抽象クラスは抽象メソッドではないメソッドをもつこともあります。)

抽象メソッドはこのように書かれていますが
abstract public void dispName();
{ } がないですね。ふつうはこういう風に書きますよね。
public void dispName(){
    System.out.println("製品Aです");
  }
{ } が抽象メソッドにないのは、抽象メソッドが何の働きもしないから必要ないためです。この{ } の内容はそれぞれのサブクラスで再度書いてやる必要があります。この{ }の内容はメソッドの実装と呼びます。メソッドの実装を書いてあげることを実装すると呼びます。

さて、ここでようやくインターフェイスの話をすることができます。インターフェイスとはなんでしょうか。java以外では、インターフェイスとは簡単にいえばそのプログラムの代表的な操作画面とかコントロールパネルを指します。

じゃあjavaのインターフェイスってなによ。例えば、ビデオ・コンポ・ウォークマン・などの音楽プレイヤー系のプログラムを作ることを考えます。このとき、これらの音楽プレイヤー系は、種類に関わらず少なくとも

public play(); //音楽を再生するメソッド。
public stop(); //音楽を停止するメソッド。
public next(); //次の音楽に行くメソッド。
public back(); // 前の音楽に戻るメソッド。

というような基本的なインターフェイスを持っているべきですね。このような代表的インターフェイスに対して java では interface というものが使われます。

すなわち、それぞれのサブクラスの実装の元となるような抽象メソッドを持つ抽象クラスを、インターフェイス(interface)と呼び、次のように書くことができます。抽象クラスと違って、インターフェイスは抽象メソッドしか持つことができません。
interface ongakuPlayerInterface {
    public play();
    public stop();
    public next();
    public back();
}
インターフェイスの場合、自動的に abstract public 修飾子がつけられるのでそれらを書く必要はありません。

このインターフェイスを継承するのが implements です。それぞれのサブクラスがこのインターフェイスを継承し、実装します。

interface ongakuPlayerInterface {
    public play();
    public stop();
    public next();
    public back();
}

class iPod implements ongakuPlayerInterface {
    public play(){
    //実際の操作を記述する(メソッドの実装)
    }

    public stop(){
    //実際の操作を記述する(メソッドの実装)
    }

    public next(){
    //実際の操作を記述する(メソッドの実装)
    }

    public back(){
    //実際の操作を記述する(メソッドの実装)
    }
}

class walkman implements ongakuPlayerInterface {
    public play(){
    //実際の操作を記述する(メソッドの実装)
    }

    public stop(){
    //実際の操作を記述する(メソッドの実装)
    }

    public next(){
    //実際の操作を記述する(メソッドの実装)
    }

    public back(){
    //実際の操作を記述する(メソッドの実装)
    }
}
上の例ではiPodクラスとwalkmanクラスがインターフェイスを継承、メソッドの実装をしていますね。これならメソッド名の混乱もしません。また、iPodやwalkmanに関わらず、ongakuPlayerというものがどんなインターフェイスを持っているべきなのかもよくわかります。こんなふうに使われるのがjavaのインターフェイスです。

実際にコードを書いてみる

class Test{
  public static void main(String args[]){
    seihinA a = new seihinA();
    a.dispName();
    a.dispCompany();  
  }
}

interface base{
  public void dispName();
  public void dispCompany();
}

 class seihinA implements base{
  public void dispName(){
    System.out.println("製品名はseihinAです");
  }
 public void dispCompany(){
    System.out.println("会社名はCompanyAです");
 }
}

これが実行結果。


インタフェースを実装するクラスのことを実装クラスと呼びます。上の例では seihinA が実装クラスです。実装クラスは普通のクラスなので他のクラスを継承(extends classA)することもできますし、他のインターフェイスの多重継承もできます(implements interfaceA, interfaceB, interfaceC)。

ただし、クラスの多重継承(extends classA, classB, classC)はできません。クラスの多重継承は実装クラスだけでなく、ふつうのクラスもできません。

ちなみに interface と ArrayList を使うとこんなこともできます。

import java.util.ArrayList;

class Test{
  public static void main(String args[]){
  seihinA a = new seihinA();
  seihinB b = new seihinB();

  ArrayList<String> seihinInformation = new ArrayList<String>();

  seihinInformation.add(a.dispName());
  seihinInformation.add(b.dispName());

  seihinInformation.add(a.dispCompany());
  seihinInformation.add(b.dispCompany());

  for (String seihin : seihinInformation)
  {
      System.out.println(seihin);
  }

  }
}

interface base{
  public String dispName();
  public String dispCompany();
}

 class seihinA implements base{
  public String dispName(){
    return ("製品名はseihinAです");
  }
  public String dispCompany(){
    return ("会社名はCompanyAです");
  }
 }

 class seihinB implements base{
    public String dispName(){
    return ("製品名はseihinBです");
  }
  public String dispCompany(){
    return ("会社名はCompanyBです");
  }
}

実行結果。

僕にはよくわからないけどこういう書き方は役に立つらしい。