LoginSignup
1
0

More than 5 years have passed since last update.

おいでよ Interfaceの森

Last updated at Posted at 2018-12-03

僕が勉強し始めたときに勝手に定義した3大なんであるのこの構文のひとつ、Interfaceさん。

この人がどういうときに使われるの?
果たして本当に必要な構文なの?

というところを紐解いて行こうと思います。

ちなみに、どうてもいいですが残りの3大なんであるのこの構文はextendsとabstractです。若気の至り。

Interfaceってなんぞや

Interface(いんたーふぇいす)というのは接触面、中間面を表す英単語なんだそう。(Wikipediaより)
パソコンについてるUSBなんかもパソコンと、色々な周辺機器をつなぐためのインターフェイスなんて呼ばれますよね。
これは色々な周辺機器がそれぞれ独自のコネクタだったら接続するときにめんどくさすぎるので、USBという規格に従って共通化されているからなのですが。

そんな感じで、他のクラスと共通の入出力などをInterfaceを実装することで実現することができます。やっていこう。

Interfaceのつくりかた

JavaでInterfaceを定義するにはinterfaceキーワードを使います。
Interfaceにはメンバ変数と抽象メソッドのみを定義することができます。

メンバ変数には自動的にpublic static finalの扱いになるので、定数としてのみ使うことができます。

メソッドは抽象メソッドになるので、Interfaceに処理を定義することはできず、メソッドの名前・返り値・仮引数のみ定義できます。

ExampleInterface.java
interface ExampleInterface{
  int getNum();
  void setNum(int num);
}

で、これを使うクラス側でimplementsキーワードを使って実装してあげます。
implementsは「実装」という意味なんですって。

ExampleClass.java
class ExampleClass implements ExampleInterface{
  int num = 10;

  @Override
  int getNum(){
    return num;
  }

  @Override
  void setNum(int num){
    this.num = num;
  }
}

前述したことの繰り返しになりますが、Interfaceに定義したメソッドは勝手に抽象メソッドになるので、必ずオーバーライドする必要があります。

こんな感じでとりあえず、今までメッチャメチャ書いてきたgetterとsetterをInterfaceにして実装してみました。

Interfaceの便利な使い方

キャストできる

継承したときのようにInterfaceもキャストができます。

とりあえず、適当なクラスを作りました。
Interfaceはさっきのを使います。

ExampleInterface.java
interface ExampleInterface{
  int getNum();
  void setNum(int num);
}

適当なクラスAとBを作ります。

ClassA.java
class ClassA implements ExampleInterface{
  int num = 10;

  @Override
  int getNum(){
    return num;
  }

  @Override
  void setNum(int num){
    this.num = num;
  }
}
ClassB.java
class ClassB implements ExampleInterface{
  int num = 20;

  @Override
  int getNum(){
    return num;
  }

  @Override
  void setNum(int num){
    this.num = num;
  }
}

じゃあ、こいつ動かしてみますか。
Interfaceの長所を使わずに適当に出力してみます。

RunClass.java
class RunClass{
  public static void main(String[] args){
    ClassA classA = new ClassA();
    ClassB classB = new ClassB();

    printNum(classA);
    printNum(classB);
  }

  static void printNum(ClassA classA){
    System.out.println(classA.getNum());
  }

  static void printNum(ClassB classB){
    System.out.println(classB.getNum());
  }
}

説明をわかってもらうためにだいぶめんどくさい書き方しました。
今、定義したクラスが2つしかないからいいけど、もし他にもClassCとかClassDとか増えて来たら大変ですよね。

じゃあ、Interfaceの型にキャストして処理してみましょう!

RunClass.java
class RunClass{
  public static void main(String[] args){
    ClassA classA = new ClassA();
    ClassB classB = new ClassB();

    printNum(classA);
    printNum(classB);
  }

  static void printNum(ExampleInterface instance){
    System.out.println(instance.getNum());
  }
}

こんな感じでExampleInterfaceを実装したクラスはすべてprintNumメソッドで処理できるようになりました。

このように実装したすべてのクラスで共通の名前のメソッドがあることを約束したいときに利用できるんじゃないかなと思います。

複数実装ができる

extendsキーワードによる継承は2つも3つもクラスを継承することはできませんでしたが、Interfaceはできます

パソコンにUSBだけじゃなくてイヤホンを挿すアナログ端子とか、LANポートがあったりしますよね。
そんな感じで、Interfaceをガシガシ追加することで、様々な入出力に対応させることができます。

なので、Interfaceはあくまでも入出力関連のメソッドを実装するのに利用し、ゴリッゴリの処理を書くのに使うべきではないと思います。

ひとつのクラスが機能を持ちすぎていると、1つのファイルに1000行を超えたりとかしてやべぇことになってしまい、どこに何を書いたかわからなくなるのでやるべきではありません。

なので、ゴリッゴリの処理を実装したいときは抽象クラスにして、また他のクラスを継承したくなったらそもそも機能を切り分けて別のクラスを作ることを考えたほうがいいでしょう。

お前は○○する係な!と、ひとことで言い表せるくらいがベストなんじゃないかな...?

シメ

Interfaceと抽象クラスの使い分けは誰もが一度は直面する問題みたいなので、自分の中での最適解が見つかるまではGoogle先生と仲良くなって、Qiitaのエントリとか、なんちゃらエンジニア塾の記事を読んでみたらいいんじゃないかなって思います。

以上!

参考

【Java入門】interface(インタフェース)の使い方総まとめ

1
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0