Javaの修飾子(static、final、abstract)とインターフェイスについて

Javaの修飾子であるstaticとfinalについて、まずは見ていきます。

staticはフィールドとメソッドに指定し、指定されたフィールドとメソッドは静的フィールドと静的メソッドになります。静的フィールドと静的メソッドはインスタンスを生成しなくても使うことができます。

finalはクラス、フィールド、メソッドに指定します。finalが指定されると変更ができなくなります。

static、finalの用途を整理したものです。

次にabstractです。

abstractは抽象メソッドの宣言に指定します。抽象メソッドとは具体的な処理を書かずプロトタイプ(戻り値と引数)のみを定義したメソッドのことです。抽象メソッドが1つでもあるクラスを抽象クラスと呼びます。抽象クラスのインスタンスは生成することができません。

abstractの用途を整理したものです。

抽象メソッドを持つクラスにはabstract指定が必要です。無いとコンパイルエラーになります。抽象メソッドがない場合でもクラスにabstract指定は可能です。あえて継承して使ってもらいたい場合はクラス修飾子にabstractをつけます。

最後にインターフェイスについてです。

インターフェイスは定数フィールドと抽象メソッドのみで構成されたクラスです(Java8からはデフォルトメソッドとスタティックメソッドが追加されましたがこれについては後述します)。インターフェイスには次のような特徴があります。

  • インターフェイスのすべてのフィールドは public static final が指定されているとみなされる。
  • インターフェイスのすべてのメソッドは public abstract が指定されているとみなされる。

そのため以下のインターフェイスはまったく同じものです。

インターフェイスのフィールドとメソッドはpublicであるため、インターフェイスのアクセス制限はインターフェイス自身につけられたアクセス修飾子によって決まります。

public interface Keisan1 { ・・ } とした場合、interface句の前にあるpublicがインターフェイス自身につけられたアクセス修飾子となります。

ここからはJava8から追加されたインターフェイスの機能についてです。

インターフェイスの抽象メソッドでは処理の記載はしないのですが、デフォルト処理の記載ができるようになりました。このデフォルト処理を記載したメソッドをデフォルトメソットと呼びます。デフォルト処理というのは、インターフェイスを実装したクラスがインターフェイスに記載されたデフォルト処理をそのまま使う場合に限り、メソッドのオーバーライドが不要となるものです。デフォルトメソッドの宣言には、default修飾子をつけます。

デフォルトメソッドは実装するクラス側のコーディング量を減らすために導入されたものです。実装する側のクラスで、どのクラスも同じ処理となる場合に有効です。

またJava8からはインターフェイスでも静的メソッドが使えるようになりました。クラスと同じようにstatic句をつけることで静的メソッドになります。インターフェイス名.メソッド名 で他のクラスから静的メソッドを呼べます。

インターフェイスのデフォルトメソッドと静的メソッドを使用した例を示します。

Helloインターフェイスではデフォルトメソッドと静的メソッドを宣言します。HelloEnクラスではHelloインターフェイスを実装しますが、デフォルトメソッドをそのまま使います(オーバーライドしません)。HelloJpクラスではHelloインターフェイスを実装して、処理を記載します(オーバーライドします)。MainSampleクラスで、デフォルトメソッド(HelloEnインスタンスのメソッド)、オーバーライドしたメソッド(HelloJpインスタンスのメソッド)、Helloインターフェイスの静的メソッドの呼び出しを行います。

ソースコードは以下です。

Hello.java


public interface Hello {

	//デフォルトメソッド
	default void hello() {
		System.out.println("Hello.");
	}

	//静的メソッド
	static void goodBye() {
		System.out.println("Good bye.");
	}

}

HelloEn.java


public class HelloEn implements Hello {
	//何もしない
}

HelloJp.java


public class HelloJp implements Hello {

	//オーバーライドする
	public void hello() {
		System.out.println("こんにちは");
	}
	
}

MainSample.java


public class MainSample {

	public static void main( String[] args ) {

		Hello h1 = new HelloEn();
		Hello h2 = new HelloJp();

		//デフォルトメソッドを呼ぶ
		h1.hello();

		//オーバーライド下メソッドを呼ぶ
		h2.hello();

		//静的メソッドを呼ぶ
		Hello.goodBye();		
		
	}
}

実行結果は以下のようになります。

$ java MainSample
Hello.
こんにちは
Good bye.

なお、default修飾子とstatic修飾子を合わせての指定(static default void hello(). . .)はできませんでした。コンパイルエラー「修飾子staticとdefaultの組合せは不正です」になります。

Javaのアクセス修飾子とprivateなコンストラクタについて

Javaのアクセス修飾子の適用範囲をまとめてみました。アクセス修飾子とは、クラス、フィールド、メソッドなどの前に付けるキーワードで他のクラスからのアクセス制限を行います。

クラスやインターフェイスは使われることで役に立つので、基本的に他のクラスに公開されます。クラスやインターフェイスのアクセス修飾子はpublicにするか、指定しないかのどちらかとなります。

Javaのソースファイル(.javaのファイル)にはアクセス修飾子が指定なしのクラスを複数記載することができますが、publicとなるクラスは1つしか記載できません。またpublicとなるクラスがある場合、ファイル名はクラス名と同じにする必要があります。

フィールドやメソッドにもアクセス修飾子があります。フィールドやメソッドに付けられるアクセス修飾子には public、protected、private、指定なしの4つがあります。

クラスのアクセス修飾子とフィールドやメソッドのアクセス修飾子が異なっていた場合にどうなるか?ですが、クラスのアクセス制限のほうが優先されます。

クラスのアクセス修飾子が指定なしだった場合、そのクラスのフィールドやメソッドがpublicであったとしても、異なるパッケージにあるクラスからはそのクラスのフィールドやメソッドにアクセスはできません。

インターフェイスのフィールドやメソッドはすべてpublicとなります。publicを指定しなかったとしてもデフォルトでpublicとみなされます(フィールドやメソッドにpublicをつけてもつけなくても同じということ)。ですのでインターフェイスのフィールドやメソッドのアクセス制限はインターフェイス自体につけられたアクセス修飾子によって決まります。

コンストラクタのアクセス修飾子もフィールドやメソッドと同じく public、protected、private、指定なしの4つとなります。アクセス制限もフィールドやメソッドと同じになります。

コンストラクタがprivateだった場合ですが、他のクラスからインスタンスを生成できなくなります(自分自身でしかインスタンスを生成できない)。privateであるコンストラクタの用途などあるのだろうか?と思うかもしれません。

代表的なクラスでは、Mathクラスのコンストラクタはprivateになっています。Mathクラスはすべてのフィールドとメソッドがstaticで宣言されているのでMathクラスのインスタンスを生成する必要がないのです。

他のクラスからインスタンスを生成されたくないときはコンストラクタをprivateにします。


public class A {

	//コンストラクタ
	private A() {
		;
	}

	public static void methodX() {
		; // 処理を記載
	}
}

またGoFのデザインパターンの1つであるSingletonパターンでもprivateなコンストラクタを使っています。Singletonパターンではクラスのインスタンスが1個しか存在しないことを保証します。

Singletonパターンの実装例です。


public class Singleton {

	private static Singleton s = new Singleton();

	//コンストラクタ	
	private Singleton() {
		;
	}

	public static Singleton getInstance() {
		return s;
	}

	public void methodX() {
		; // 処理を記載
	}

}

他のクラスからはgetInstanceメソッドを呼び出して、Singletonクラスのインスタンスを取得します。SingletonクラスのmethodXメソッドのアクセス修飾子はprivate以外にします。

使用例です。


public class MainSample {

	public static void main( String[] args ) {

		Singleton s = Singleton.getInstance();
		s.methodX();

	}
}

このようにあえて他のクラスからインスタンスを生成させないために、privateのコンストラクタがあるようです。