検索

キーワード


【Java】インターフェースの default と static それぞれの使い方

  • 公開日:2020-09-03 17:25:02
  • 最終更新日:2021-01-25 13:23:07
【Java】インターフェースの default と static それぞれの使い方

こんにちは、駆け出しプログラマーの若江です!

ここでは初学者として学習を終えた私からアウトプットの意味も込めて、

Java8 から新たに実装されたインターフェースの default メソッドと static メソッドについて紹介させていただきます。

できる限り初学者が理解しやすい内容として紹介させていただくので、参考となれば幸いです!


関連記事リンク:インターフェースの紹介 / 継承とオーバーライドの紹介 / メソッドの紹介 / インスタンスの紹介 / アクセス修飾子の紹介 / static修飾子の紹介 / superの紹介

Java8 で実装されたインターフェースの default メソッドと static メソッド

インターフェースは元々クラスへ実装することを目的として、

中身の書かれていないメソッドを用意していました。

しかし Java8 からインターフェースに新機能として default メソッドと static メソッドが実装されたことにより、

インターフェース自体が中身のある(具象)メソッドを持てるようになりました。

ここではインターフェースの default メソッドと static メソッドについて紹介させていただきます。


default メソッド

Java8 から加わった新機能がdefault メソッドです。

default メソッドは、インターフェースの中で具象メソッドを書くことができるメソッドです。

通常のメソッドの書き方に似ていて、アクセス修飾子を書かずに default を書く以外は同じ構文です。

・default メソッドの基本構文: default 戻り値の型 メソッド名(引数の型 引数) { 処理内容 }

 ※ Object クラスのメソッド(toString(), hashCode(), equals(Object))は defaultメソッドとして使えないので注意が必要です。


◆ default メソッドの書き方例

// default メソッド
default void defaultName(String str) {
}

具象メソッドが書けるようになってもインターフェースはクラスへの実装が必要です。

そのためメソッドのアクセス修飾子は暗黙的に public となっています。


インターフェースに具象メソッドが書けるようになったことで、

default メソッドについてはクラスでの実装が不要となり、コーディングの負担が削減できるようになりました。

また、後からインターフェースへ新たなメソッドを追加したときも、

default メソッドを使うことで実装クラスのメソッド修正はしなくてよくなります。


default メソッドの使い方

インターフェースをクラスへ実装すれば、default メソッドで書かれたメソッドは

クラス側で特に実装を必要とせず、インスタンスから default メソッドの使用が可能となります。

実装クラスには何も書かないで default メソッドを呼び出すサンプルコードを見てみましょう。


◆ default メソッドの使用例

【インターフェース】 default メソッドを作成

public interface DefaultTestSample {
	default String name() {
		return "テスト";
	}
}

【実装クラス】 上記インターフェースの実装のみ

public class DefaultTestSample2 implements DefaultTestSample {
}

【実行】 インターフェースの default メソッドを呼び出し

public class Test{
	public static void main(String[] args) {

		DefaultTestSample sample = new DefaultTestSample2(); // インスタンス化
		System.out.println(sample.name()); // 結果:「テスト」を表示
	}
}


負担が減るなど、かなり便利になる default メソッドですが、具象メソッドが持てるようになったことにより

インターフェースの特徴である多重継承について注意点が生まれました。

もともとインターフェースのメソッドには処理内容が書かれていなかったため、

多重継承の問題が発生しなかったのですが、今回 default メソッドの実装によりその危険性が出てきました。


多重継承による default メソッド

default メソッドが使えるようになったことで、

インターフェースが具象メソッドを持てるようになりましたが、

2つ以上のインターフェースを実装したクラスが、

同じ名前の別処理をするメソッドを2つ以上持つとどうなるのでしょうか?

 例) インターフェース①(メソッドA)

    ➡継承インターフェース②(メソッドA処理タイプa)インターフェース③(メソッドA処理タイプb)

    ➡インターフェース②③を実装クラス④(メソッドA処理タイプa, メソッドA処理タイプb を保持)


このままでは、クラス④に同じメソッド名の「メソッドA」が2つあるためエラーとなります。

このような場合は super を使って明示的にどのインターフェースのメソッドA を使うか指定することで、

エラーが解消されます。

・super の基本構文(重複メソッド実装時): インターフェース名.super.メソッド名( 引数 )


上記 super の基本構文を使ったインターフェースのサンプルコードを確認してみましょう。


◆ super の使用例

【インターフェース①】 名前が渡されるとオウム返しする defaultName メソッド作成

public interface DefaultTest {

	// default メソッド
	default String defaultName(String str) {
		return str;
	}
}

【インターフェース②】 インターフェース①のメソッドをオーバーライドして名乗るメソッド

public interface DefaultTest2 extends DefaultTest{

	// オーバーライド default メソッド
	default String defaultName(String str) {
		return "私の名前は" + str + "です。";
	}
}

【インターフェース③】 インターフェース①のメソッドをオーバーライドして否定するメソッド

public interface DefaultTest3 extends DefaultTest {

	// オーバーライド default メソッド
	default String defaultName(String str) {
		return "私の名前は" + str + "ではない。";
	}
}

【クラス④】 インターフェースの defaultName メソッドをオーバーライドして super で②を呼び出し

public class DefaultTestImpl implements DefaultTest2, DefaultTest3 {

	// メソッドをオーバーライドして DefaultTest インターフェース②の defaultName メソッド呼び出し
	public String defaultName(String str) {
		return DefaultTest2.super.defaultName(str);
	}
}

【インスタンスを生成するクラス】 インスタンス生成して上記クラスのメソッドを呼び出し

public class Test{
	public static void main(String[] args) {

		DefaultTestImpl test = new DefaultTestImpl();
		System.out.println(test.defaultName("田中")); // 結果:「私の名前は田中です。」を表示
	}
}


super を使ってインターフェース③は呼ばずに②のメソッドを呼び出せました。(名乗るメソッド)

上記からわかる通り親インターフェースを継承した子インターフェースと、

子インターフェースを実装したクラスの関係では、親・子インターフェースのメソッド名は同じになりますが、

super で呼ぶのはクラスと直接関係のある、オーバーライドした子インターフェースのメソッドです。

 例) 親インターフェース(メソッドA処理a) ➡継承➡ 子インターフェース(メソッドA処理b)

    子インターフェース実装➡ クラス(メソッドA処理b)



static メソッド

default メソッドと同じタイミングで新たに実装された機能が static メソッドです。

インターフェースの static メソッドも、具体的な処理内容を書くことができるメソッドです。

・インターフェースの static メソッド基本構文: static 戻り値の型 メソッド名(引数の型 引数)


static メソッドとなったため、default メソッドのようにインスタンス生成をしなくても、

クラスから直接呼び出すことが可能となります。

static メソッドの作成と呼び出し方法をサンプルコードで確認してみましょう。


◆ static メソッドの作成・呼び出し例

【static メソッド作成インターフェース】

public interface DefaultTest {

	// static メソッド
	static String staticName() {
		return "スタティックメソッド";
	}
}

【static メソッド呼び出しクラス】


public class Test{
	public static void main(String[] args) {

		// インスタンス化しなくても、implements しなくても使える
		System.out.println(DefaultTest.staticName()); //結果:「スタティックメソッド」を表示
	}
}


static メソッドは通常のクラスでの扱いと同様のため、

default メソッドのようにオーバーライドすることはできません。

呼び出し方も「インターフェース名.メソッド名」と明示的で super は必要ありません。


static メソッドのアクセス修飾子 private

Java9 からは static メソッドに private のアクセス修飾子が設定できるようになりました。

private static メソッドを持つインターフェース自身で使うメソッドとして存在し、

これは default メソッドにはない機能です。


◆ private static メソッドの例

public interface DefaultTest {

	// static メソッド
	static String staticName() {
		return staticName2() + "スタティックメソッド";
	}

	// private 付き static メソッド
	private static String staticName2() {
		return "Hello";
	}
}
public class Test{

	public static void main(String[] args) {

		System.out.println(DefaultTest.staticName()); //結果:「Hello スタティックメソッド」を表示
	}
}


static メソッドから static メソッドへのアクセスはもちろん、

default メソッドから static メソッドへのアクセスも可能です。

しかしインターフェースの外からは、たとえ実装クラスであってもアクセス不可能となっています。

 ※ static の特性上 static メソッドから default メソッドへの直接的なアクセスはできません。


まとめ

今回紹介した default メソッドと static メソッドは Java8 から実装された機能のため、

比較的まだ新しく目にする機会は少ないかもしれません。

しかし便利な機能であるためこれから新しく作られるプロジェクトなど、

活用できるチャンスがあれば、注意点に気を付けながら積極的に活用することをお勧めします。


関連記事リンク

インターフェースの紹介 / 継承とオーバーライドの紹介 / メソッドの紹介 / インスタンスの紹介 / アクセス修飾子の紹介 / static修飾子の紹介 / superの紹介


【著者】

若江

30代で異業種となるIT業界へ転職した駆け出しのプログラマです。これまで主に Java や Ruby、HTML/CSS を使って学習を目的としたショップサイトや掲示板サイトの作成を行いました。プログラマとしての経験が浅いからこそ、未経験者の目線に近い形で基礎の紹介をしていきたいと思います。

よく読まれている記事
【Java】JSPでタグライブラリを使う(JSTL)

【Java】JSPでタグライブラリを使う(JSTL)

こんにちは。エンジニアの新田です!ここでは、システムエンジニアとして働いている私が、システム開発手法や開発言語について紹介していこうと思います。今回は、JSPの標準タグライブラリ「JSTL」について紹介します。Javaについて勉強している方、Webアプリケーションを構築したいと思っている方の参考になれば幸いです!関連記事リンク: 【Java】JSPの基本的な構文/【Java】JSPのアクションタグ

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!そもそもStringとは何?『 String 』... Java言語において文字列のデータ型を指します。基本デ

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!Stringクラスformatメソッドの文字列整形【java.utilパッケージ】Formatterクラスfo

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者にも✅、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!文字列を扱う3つのクラス【java.langパッケージ】java.langパッケージの文字列を扱うクラスにはS

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!プリミティブ型と参照型プログラム開発では型を持った変数を使ってデータのやり取りをしますが、データ型によって仕様