2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

20分でわかる? JavaのInterfaceの基本

Last updated at Posted at 2024-08-10

サンプルコード

本記事ではゲームプログラムっぽいサンプルコードとともに、Interfaceそのもの・呼ばれる側・呼ぶ側の解説をする。Interfaceって何?という方向けの記事です。

Interfaceファイル

メソッド(ふるまい)の定義を記載したファイル。
クラスではない。

ゲームプログラムっぽいもの①.java
/** プレイヤーがアクセス可能である。*/
public interface アクセス可能なもの{

    /** アクセスされたときのふるまい。*/
    public void アクセスする();
}

上記の通り、メソッドの中身も空っぽでよく、
メソッドの定義(平たく言うと、呼び出し方)さえ書かれていればOK、というのがInterface。

乱暴に言うと、中身空っぽの定義ファイルである。

Interfaceとして呼び出される側(Interfaceの実装クラス)

Interfaceは他のクラスに実装(Implement)されることで、使えるようになる。

ゲームプログラムっぽいもの②.java
public class 宝箱 implement アクセス可能なもの{

    public void アクセスする(){
        //中身を獲得する処理。
    }
}

public class 商人 implement アクセス可能なもの{

    public void アクセスする(){
        //取引画面を開く処理。
}

メソッドの名前や引数などはInterfaceに従う必要がある。
が、メソッドの中身の処理は実装クラス側が好きに決められる。
なので、処理は同じでも良いし、全く違っても良い。自由。

上記例の「商人」と「宝箱」というのは、客観的に見て、関連が薄い機能ではあるが、
「プレイヤーがアクセス可能」という1点だけに注目すると、共通であるともいえる。

乱暴な言い方にはなるが、
Interface記載のふるまいを実装しよう!と思ったクラスには、Interfaceは実装してよい
(ここでは「プレイヤーがアクセス可能である」というのが「ふるまい」)

注意点だが、Interfaceを実装(Implements)する場合、Interfaceのメソッドは
漏れなく使えるようにしておかないといけない。
上記の例では「アクセスする」メソッドをクラスにて使える状態にしておく必要がある。
そうでないと、コンパイルエラーになってしまう。

Interfaceを呼び出す側

呼び出す処理のほうも書いてみる。
以下を見るとわかるが、呼び出す側は、Interfaceと階層的に関係する必要はなく、Interface名と呼び出すメソッドを知っているだけで良い。

ゲームプログラムっぽいもの③.java
    public void 〇ボタンを押す(){

    //近隣のアクセス可能な対象から最も近いものを取得する機能(詳細略)
    アクセス可能なもの accessable=getAccessable(); 

    //取得した対象にアクセスする。
    accessable.アクセスする();
    }
}

ここで注目してほしいのだが、
呼び出す側のコードには、「宝箱」「商人」といった要素が一切出てきていない。
「アクセス可能なもの」に対して「アクセスする」という抽象的な表現になっている。

抽象的に書ける、ということは、実は非常にありがたい。なぜなら、
・宝箱に対する呼び出しコード
・商人に対する呼び出しコード
をそれぞれに書く必要がないからである。

もっと言うと、「ちょっとレアな宝箱」だの「秘密のボタン」だの、
アクセス可能な対象を増やされても安心だといえる。

<<以降、抽象的にあつかえるというのは原則良い、という立場で記載します>>

Interfaceの使われどころ

Interfaceが使われる場合、下記のうちの1つ、もしくは組み合わせが目的であることが多い。

自由な継承

クラスの継承元、すなわち「親」は1つのみ、というのがJavaの大原則、ルールである。

BadExtends.java
public class Child extends Parent1,Parent2{
 //コンパイルエラーになる。
}

が、Interfaceはいくつでも実装元として使える。

GoodImplements.java
public class Child Implements Interface1,Interface2{
 //問題なし。
}

抽象的なプログラミングを行う際、
Interface1という抽象名でも扱いたいが、Interface2という抽象名でも扱いたい・・・
というケースはよくある。
Interfaceは多重継承可能であるので特に気にせず、両方のInterfaceを実装できる。

ソースに対するマーカー

Interfaceは中身が空っぽ、かつクラスにいくつも実装できる、という特徴は、
クラスに何かしらのマーキングをしたいというニーズにぴったりである。
この思想で使われているのがアノテーション(@xxx)という機能である。
アノテーションは、@InterfaceというInterfaceの一機能である。

自動生成の殻として

interfaceのメソッドは中身が空であり、
かつ、実装クラスが別で生成されるという特徴は、
自動生成ライブラリの思想とよく適合する。
(作りたい内容だけ定義し、中身はライブラリが自動生成したものを作成する)
domaやlombokなど。

Interfaceでも中身を書きたいという場合

ガワもいいけど、やはり処理を共通化したい、というケースは往々にして発生する。
それに対するアンサーが、defaultメソッドと、(Interfaceの)staticメソッドである。

defaultメソッド

defaultメソッドという仕組みがあり、中身の処理を記載できる。

Example.java
/** プレイヤーがアクセス可能である。*/
public interface Example{

    /** 共通的な処理。*/
    public default void 共通的な処理(){
        //共通的な処理。
    }
}

staticメソッド

こちらも同様に、中身の処理を記載できる。

Example2.java
/** プレイヤーがアクセス可能である。*/
public interface Example2{

    /** 共通的な処理。*/
    public static void 共通的な処理(){
        //共通的な処理。
    }
}

defaultとの使い分けは、基本的には
staticというもののふるまい(インスタンス化されない、継承できない、など)に注意していただければよい。

余談

  • Interfaceには、定数も定義できる。(public static finalな変数)
  • Interfaceのクラス・メソッドは原則、publicであるとして扱われる。
  • Java以外では、Interfaceという名前の機能はあまり見たことが無い。抽象クラスを使うことも多い気がする。動的型付け言語だと、ダックタイピングという思想が引き合いに出されることが多い。
  • 後半ちょっと力尽きてます。

参考文献

徹底攻略 Java SE11 Silver問題集(インプレス)

2
1
0

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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?