目次 | | | 索引 Java言語規定
第2版

9. インタフェース

インタフェース宣言は,メンバをクラス,インタフェース,定数及び抽象メソッドとする新しい参照型を導入する。この型は実装をもたないが,その抽象メソッドに実装を提供するクラスは,そのインタフェースを実装すると呼ぶ。

入れ子になったインタフェースは,その宣言が別のクラス又はインタフェースの本体内で起こる任意のインタフェースとする。最上位のインタフェースは,入れ子ではない一つのインタフェースとする。

9.では,すべてのインタフェースすなわち最上位の型(7.6)及び入れ子(8.5, 9.5)であるインタフェースの共通の意味について記述する。特定の種類のインタフェースへ特化した詳細は,その節で記述する。

プログラムは,関係しているクラスが共通の抽象上位クラスを共有すること又はメソッドをObjectに追加することを不要とするために,インタフェースを使用することができる。 インタフェースは,一つ又は複数の他のインタフェースの直接的拡張(direct extension)と宣言してもよい。これによって,隠ぺいされるいかなるメンバ及び定数以外の,インタフェースが拡張したすべてのメンバ型,抽象メソッド及び定数を,暗黙的に規定する。

クラスは,一つ以上のインタフェースを直接的に実装する(directly implement)と宣言してもよい。これによって,そのクラスの任意のインスタンスはインタフェースによって規定されるすべての抽象メソッドを実装する。クラスは,必然的に,その直接的上位クラス及び直接的上位インタフェースのすべてのインタフェースを実装する。この(多重)インタフェース継承は,オブジェクトがいかなる実装も共有せずに(多重の)共通的な振る舞いをサポートすることを可能とする。

宣言型をインタフェース型とする変数は,その値として,指定されたインタフェースを実装すると宣言されるクラスのインスタンスであるオブジェクト参照をもっていてよい。クラスがインタフェースのすべての抽象メソッドをたまたま実装しているのでは十分でない。そのクラス又はその上位クラスの一つは,そのインタフェースを実装することが本当に宣言されていなければならない。そうでないときには,クラスはそのインタフェースを実装するとは考えない。

9.1 インタフェース宣言

インタフェース宣言(interface declaration)は,名前付きの新しい参照型を規定する。

インタフェース宣言中のIdentifierは,インタフェースの名前を規定する。インタフェースが取り囲むクラス又はインタフェースのどれかが,インタフェースの単純名と同じ名前ならば,コンパイル時エラーが発生する。

9.1.1 インタフェース修飾子

インタフェース宣言は、インタフェース修飾子(interface modifier)を包含してもよい。

アクセス修飾子publicは,6.6で記述する。 すべての修飾子が,すべての種類のインタフェース宣言に適用できるわけではない。アクセス修飾子protected及びprivateは,直接的に取り囲んでいるクラス宣言(8.5)内のメンバインタフェースにのみ属する。また,これらは8.5.1で記述する。アクセス修飾子staticはメンバインタフェース(8.5, 9.5)にのみ属する。同じ修飾子が一つのインタフェース宣言で二回以上出現するとき,コンパイル時エラーが発生する。

9.1.1.1 abstract インタフェース

すべてのインタフェースは,暗黙的にabstractとする。この修飾子は,もはやインタフェースに対しては意味がなく,新しいプログラムでは使用しないことが望ましい。

9.1.1.2 strictfp インタフェース

strictfp修飾子の効果は,インタフェース宣言内のすべての型float又は型double表現を明示的にFP厳密にすることとする。

このことは,インタフェース内で宣言されたすべての入れ子にされた型は,暗黙に型strictfpであるという意味を含む。

9.1.2 上位インタフェース及び下位インタフェース

extends節が提供されれば,宣言されるインタフェースは、他の名前付けされた各インタフェースを拡張し,したがって,他の名前付けされたインタフェースのメンバ型,メソッド及び定数を継承する。宣言されるインタフェースの直接的上位インタフェース(direct superinterface)とは,これらの名前付けされたインタフェースとする。宣言されたインタフェースを実装するクラスは,このインタフェースが拡張するすべてのインタフェースも実装することとする。

次は,明確化のために4.3の記述を繰り返す。

インタフェース宣言のextends節内の各InterfaceTypeは,アクセス可能なインタフェース型を名前付けしなければならない。そうでないときには,コンパイル時エラーが発生する。

T に直接的に依存するインタフェースI は,Iextends節中に上位インタフェースか上位インタフェース名の中の限定子のどちらか一方として記載される。次の条件のいずれかを満たす場合,インタフェースI は,参照型T に依存する。

インタフェースが自己に依存する場合コンパイル時エラーが発生する。

すべてのクラスはクラスObjectの拡張だが,すべてのインタフェースが拡張となる単一のインタフェースは存在しない。

上位インタフェース(superinterface)関係は,直接的上位インタフェース関係の推移的閉包(transitive closure)とする。次のいずれかが真ならば,インタフェースK はインタフェースI の上位インタフェースとする。

インタフェースI は,KI の上位インタフェースである時はいつもインタフェースK の下位インタフェースであると言える。

9.1.3 インタフェース本体及びメンバ宣言

インタフェース本体は,インタフェースのメンバを宣言してよい。

インタフェース型Iで宣言又は継承されるメンバmの宣言の有効範囲は,入れ子になった型宣言を含むI の本体全体とする。

9.1.4 インタフェースメンバ名へのアクセス

すべてのインタフェースメンバは,暗黙的にpublicとする。これらが,インタフェースが宣言されているパッケージの外側からアクセス可能となる条件は,6.6の規則にしたがって,そのインタフェースがpublic又はprotectedと宣言されていることとする。

9.2 インタフェースメンバ

インタフェースのメンバは,次のとおりとする。

インタフェースが,同じシグネチャ及び異なる返却値の型又は互換性のないthrows節をもったメソッドを宣言する場合コンパイル時エラーとする。

インタフェースは,そのインタフェースが拡張するインタフェースから,フィールド,クラス,そのインタフェースが隠ぺいするフィールド及び上書きするメソッドを除いたすべてのメンバを継承する。

9.3 フィールド(定数)宣言

インタフェース本体でのすべてのフィールド宣言は,暗黙的にpublicstatic及びfinalとする。冗長だが,フィールドにこれらの修飾子を,どれか又はすべて明示的に指定してもよい。

インタフェースが,ある名前をもったフィールドを宣言する場合,フィールドの宣言は,インタフェースの上位インタフェース中の同じ名前をもったフィールドのあらゆるアクセス可能な宣言を隠ぺい(hide)するという。

同じ名前をもつ二つのフィールドを宣言するインタフェース宣言の本体は,コンパイル時エラーを発生する。

インタフェースが,同じ名前(8.3.3.3)をもつ複数のフィールドを継承する可能性がある。このような状況自体は,そのままではコンパイル時エラーを発生しない。しかしながら,インタフェースの本体内で,そのフィールドがその単純名で参照されると,コンパイル時エラーが起こる。なぜならば,そのような参照はあいまいだからである。

同じフィールド宣言がインタフェースから継承されるパスが幾つかあってよい。このような状況では,フィールドは,一回のみ継承されると考えられる,また,単純名によってあいまいさなく参照できる。

9.3.1 インタフェース内でのフィールドの初期化

インタフェース本体内のすべてのフィールドは,初期化式をもたなければならない。これは定数式とする必要はない。インタフェースが初期化されるとき(12.4),変数初期化子が評価され,1回だけ代入が実行される。

インタフェースフィールドのための初期化式が単純名によって同じフィールドへの参照を含むか,又は同じインタフェース内で,ソーステキスト上,後方に宣言されている他のフィールドへの参照を含めば,コンパイル時エラーが発生する。

すなわち,以下のコード

interface Test {
	float f = j;
	int j = 1;
	int k = k+1;
}
は,二つのコンパイル時エラーを引き起こす。なぜならば,jは,jが宣言される前に,fの初期化の中で参照され,また,kの初期化はk自身を参照するからである。

微妙な点について述べると,実行時においてコンパイル時に定数を伴って初期化されるフィールドは,最初に初期化される。これは,クラス中のstatic finalフィールド(8.3.2.1)にも適用される。これは,これらのフィールドが,デフォルト初期値(4.5.5)をもつと観察されることは,たとえひねくれたプログラムでも決してないことを意味する。詳細については,12.4.213.4.8を参照のこと。

キーワードthis(15.8.3)又はキーワードsuper(15.11.2, 15.12)が,インタフェースのフィールドのための初期化表現中に現れる場合,その発生が匿名クラス(15.9.5)の本体内でない限り,コンパイル時エラーが発生する。

9.3.2 フィールド宣言の例

次にフィールド宣言に関する幾つかの(微妙な)点を例示する。

9.3.2.1 あいまいな継承フィールド

もしも,直接的上位インタフェースの二つが,同じ名前をもったフィールドを宣言したために,同じ名前をもった二つのフィールドが,インタフェースによって継承されたならば,単一のあいまいなメンバ (ambiguous member)が結果として生じる。このあいまいなメンバの使用は,コンパイル時エラーを起こす。

interface BaseColors {
	int RED = 1, GREEN = 2, BLUE = 4;
}
interface RainbowColors extends BaseColors {
	int YELLOW = 3, ORANGE = 5, INDIGO = 6, VIOLET = 7;
}
interface PrintColors extends BaseColors {
	int YELLOW = 8, CYAN = 16, MAGENTA = 32;
}
interface LotsOfColors extends RainbowColors, PrintColors {
	int FUCHSIA = 17, VERMILION = 43, CHARTREUSE = RED+90;
}
この例では,インタフェースLotsOfColorsは,YELLOWと名付けられた二つのフィールドを継承している。これ自体は,フィールドYELLOWへの単純名によるいかなる参照も含まないインタフェースと同様に問題ない。(このような参照は,フィールドのための変数初期化子内で起こることがある)

しかし,たとえインタフェースPrintColorsが値8ではなく,値3YELLOWへ与えていたものと仮定しても,インタフェースLotsOfColors内でフィールドYELLOWへの参照があれば,あいまいと見なされる。

9.3.2.2 多重継承フィールド

もしも,例えば,あるインタフェース及びこのインタフェースの直接的上位インタフェースとが,ともに,あるフィールドを宣言するインタフェースを拡張したために,その単一フィールドが複数回継承されたならば,結果は単一のメンバのみとなる。この状況自体は,コンパイル時エラーを引き起こさない。

先の節での例において,フィールドRED, GREEN及びBLUEは,インタフェースLotsOfColorsによって複数の方法,インタフェースRainbowColors及びインタフェースPrintColorsによっても継承されるが,インタフェースLotsOfColors中のフィールドREDへの参照は,あいまいであると見なさない。なぜならば,フィールドREDのただ一つの実際の宣言が含まれるからである。

9.4 抽象メソッド宣言

アクセス記述子publicは,6.6で,記述される。抽象メソッド宣言の中で複数回同じ記述子が現れた場合,コンパイル時エラーが発生する。

インタフェース本体中のすべてのメソッド宣言は暗黙的にabstractとするので,メソッド本体は,一つのセミコロンで表され,ブロックとはならない。

インタフェース本体中のすべてのメソッド宣言は暗黙的にpublicとする。

Javaプラットフォームのより古い版との互換性のために,インタフェース中に宣言されるメソッドのためのabstract記述子を冗長に指定することは,形式として許されているが,推奨しない。

インタフェースメソッドのためのpublic記述子を冗長に指定することは,形式として許されているができる限り使用しないこと。

インタフェース中で宣言されるメソッドは,staticで宣言してはいけないことに注意すること。さもなければコンパイル時エラーが発生する。なぜならば,staticメソッドはabstractになることは出来ないからである。

インタフェース中で宣言されるメソッドは,strictfp又はnative又はsynchronizedと宣言してはいけないことに注意すること。さもなければコンパイル時エラーが発生する。なぜならば,これらのキーワードは,インタフェース属性よりもむしろ実装の属性を記述するものだからである。しかしながら,インタフェース中で宣言されるメソッドは,インタフェースを実現するクラスの中でstrictfp又はnative又はsynchronizedで宣言されるメソッドによって実現してもよい。

同じシグネチャ(名前,パラメタの数及びパラメタの型(8.4.2))をもった二つのメソッドを明示的又は暗黙的に宣言するインタフェースの本体は,コンパイル時エラーとなる。しかしながら,インタフェースは,同じシグネチャ(9.4.1)をもった,幾つかのメソッドを継承してもよい。

インタフェース中で宣言されるメソッドは,finalで宣言してはいけないことに注意すること。さもなければコンパイル時エラーが発生する。しかしながら,インタフェース中に宣言されたメソッドは,インタフェースを実現するクラス中にfinalで宣言されたメソッドによって実装されてもよい。

9.4.1 継承及び上書き

インタフェースがメソッドを宣言する場合,メソッドの宣言は,インタフェースの上位インタフェースの中で同じシグネチャをもったあらゆるメソッドを上書き(override)するという。

インタフェースの中のメソッド宣言が別のインタフェースの中のメソッドの宣言を上書きする際に,メソッドが異なる返却値の型をもつ,又は一方がある返却値の型をもち,他方がvoidを返却値の型とする場合,コンパイル時エラーが発生する。さらに言えば,メソッド宣言は,上書きする任意のメソッドと衝突する(8.4.4)throws節をもってはいけない。そうでなければコンパイル時エラーが発生する。

メソッドは,シグネチャ単位に上書きされる。例えば,インタフェースが,同じ名前の二つのpublicメソッドを宣言し,下位インタフェースがそのうちの一つのメソッドを上書きする場合も,その下位インタフェースは,もう一つのメソッドを継承する。

インタフェースは,直接的上位インタフェースから,インタフェース中の宣言によって上書きされない上位インタフェースの全てのメソッドを継承する。

インタフェースは同じシグネチャ(8.4.2)をもった複数のメソッドを継承することがある。このような状況は,そのままではコンパイル時エラーを起こさない。インタフェースは全てのメソッドを継承すると見なされる。しかしながら,継承したメソッドが異なる返却値の型をもったり,一方がある返却値の型をもち,他方がvoidを返却値の型とするような任意の二つの継承されるメソッドはコンパイル時エラーを引き起こす。(この継承の場合は,throws節の衝突はエラーを起こさない。)同じメソッド宣言をインタフェースから継承するための幾つかのパスがあってもよい。この事実は,どんな困難も引き起こさず,そのままでは決してコンパイル時エラーを引き起こさない。

9.4.2 オーバロード

インタフェースの二つのメソッドが(両方とも同じインタフェース内で宣言したか,両方とも一つのインタフェースによって継承されたか,又は,一つが宣言されもう一つが継承されたか,にかかわらず)同じ名前だが異なったシグネチャをもてば,そのメソッド名はオーバロード(overload)されていると言う。この事実は,どんな困難も引き起こさず,そのままでは決してコンパイル時エラーを生じない。同じ名前だが異なったシグネチャをもつ二つのメソッドの返却値の型の間又はthrows節の間には,関係は要求されない。

9.4.3 抽象メソッド宣言の例

次に抽象メソッド宣言に関する幾つかの(微妙な)点を例示する。

9.4.3.1 例: 上書き

インタフェース内で宣言されるメソッドは,abstractで,いかなる実装も含まない。メソッドシグネチャを確定する以外に上書きメソッド宣言で達成できることは,メソッドの実装によって投げられるかもしれない例外を制限することがある。次に8.4.3.1で示す例の変形を示す。

class BufferEmpty extends Exception {
	BufferEmpty() { super(); }
	BufferEmpty(String s) { super(s); }
}
class BufferError extends Exception {
	BufferError() { super(); }
	BufferError(String s) { super(s); }
}
public interface Buffer {
	char get() throws BufferEmpty, BufferError;
}
public interface InfiniteBuffer extends Buffer {
	char get() throws BufferError;        // override
}

9.4.3.2 例: オーバロード

interface PointInterface {
	void move(int dx, int dy);
}
interface RealPointInterface extends PointInterface {
	void move(float dx, float dy);
	void move(double dx, double dy);
}
前述の例では,メソッド名moveがインタフェースRealPointInterfaceで,二つが宣言されており一つは継承されている三つの異なるシグネチャでオーバロードされている。インタフェースRealPointInterfaceを実装するいかなる非abstractクラスも,三つのメソッドシグネチャすべての実装を提供しなければならない。

9.5 メンバ型宣言

インタフェースは,メンバ型宣言(8.5)を含んでもよい。インタフェースの中のメンバ型宣言は暗黙的にstatic及びpublicとしてよい。

単純名Cをもって宣言されたメンバ型が,完全に限定された名前Nをもったインタフェースの宣言内に直接的に閉じられている場合,メンバ型は完全に限定された名前N.Cをもつ。

インタフェースがある確かな名前をもったメンバ型を宣言する場合,そのフィールドの宣言は,インタフェースの上位インタフェースの中の同じ名前をもったメンバ型のアクセス可能なあらゆる宣言を隠ぺいする(hide)という。

インタフェースは,同じ名前をもった二つ以上の型宣言を継承してもよい。単純名であることにより,あいまいに継承されるクラスまたはインタフェースを参照すると,いかなる場合もコンパイル時エラーが発生する。同じ型宣言が複数のパスによってインタフェースから継承される場合,クラス又はインタフェースは,一度限り継承されると見なされる。単純名によって,あいまいさなく参照できる。

目次 | | | 索引 Java言語規定
第2版