Javaプログラムは,関係しているクラスが共通の抽象スーパクラスを共有すること又はメソッドをObject
に追加することを不要とするために,インタフェースを使用することができる。
インタフェースは,複数の他のインタフェースの直接的拡張(direct extension)と宣言してよい。これによって,隠ぺいされるかもしれない定数以外の,インタフェースが拡張した元のインタフェース複数の他の抽象メソッド及び定数を,暗黙的に規定する。
クラスは,複数のインタフェースを直接的に実装する(directly implement)と宣言してもよい。これによって,そのクラスの任意のインスタンスはインタフェースによって規定されるすべての抽象メソッドを実装する。クラスは,必然的に,その直接的スーパクラス及び直接的スーパインタフェースのすべてのインタフェースを実装する。この(多重)インタフェース継承は,オブジェクトがいかなる実装も共有せずに(多重の)共通的な振舞いを実装することを可能とする。
宣言型をインタフェース型とする変数は,その値として,指定されたインタフェースを実装すると宣言されるクラスのインスタンスであるオブジェクト参照をもっていてよい。クラスがインタフェースのすべての抽象メソッドをたまたま実装しているのでは十分でない。そのクラス又はそのスーパクラスの一つは,インタフェースを実装するものと実際に宣言されていなければならない。そうでないときには,クラスはそのインタフェースを実装するとは考えない。
InterfaceDeclaration: InterfaceModifiersoptインタフェースを名前付けするIdentifierが,同じパッケージ内の他のクラス又はインタフェースの名前として出現すれば,コンパイル時エラーが発生する。インタフェースを名前付けするIdentifierが,そのインタフェース宣言を含むコンパイル単位における単一型インポート宣言(7.5.1)経由で知られるクラス又はインタフェースの名前として出現すれば,コンパイル時エラーが発生する。次に例を示す。interface
Identifier ExtendsInterfacesoptInterfaceBody
class Point { int x, y; }同じパッケージ内の
interface Point { void move(int dx, int dy); }
class
及びinterface
は,同じ名前をもてないので,コンパイル時エラーが発生する。
InterfaceModifiers:アクセス修飾子InterfaceModifier
InterfaceModifiers
InterfaceModifier InterfaceModifier: one of
public abstract
public
は,6.6で記述する。同じ修飾子が一つのインタフェース宣言で2回以上出現するとき,コンパイル時エラーが発生する。
abstract
とする。この修飾子abstract
は,もはやインタフェースに対しては意味がなく,新しいJavaプログラムでは使用しないことが望ましい。
extends
節が提供されれば,宣言されるインタフェースは、他の名前付けされた各インタフェースを拡張し,したがって,他の名前付けされたインタフェースのメソッド及び定数を継承する。これらの名前付けされたインタフェースは,宣言されるインタフェースの直接的スーパインタフェース(direct superinterface)とする。宣言されたインタフェースを実装するクラスは,このインタフェースを拡張し,実装となるクラスにアクセス可能なすべてのインタフェースも実装する。
ExtendsInterfaces:次は,明確化のために4.3から再度記述する。extends
InterfaceType ExtendsInterfaces,
InterfaceType
InterfaceType: TypeNameインタフェース宣言の
extends
節内の各InterfaceTypeは,アクセス可能なインタフェース型を名前付けしなければならない。そうでないときには,コンパイル時エラーが発生する。
インタフェースが直接的又は間接的にそれ自体を拡張する循環が存在すれば,コンパイル時エラーが発生する。
インタフェースに対しては,Object
に類似するものは存在しない。すなわち,すべてのクラスはクラスObject
の拡張だが,すべてのインタフェースが拡張となる単一のインタフェースは存在しない。
スーパインタフェース(superinterface)関係は,直接的スーパインタフェース関係の推移的閉包(transitive closure)とする。次のいづれかが真ならば,インタフェースKはインタフェースIのスーパインタフェースとする。
KがIのスーパインタフェースであるときはいつでも,インタフェースIがインタフェースKのサブインタフェース(subinterface)と言う。
InterfaceBody:インタフェース型で宣言されるメンバの名前の有効範囲は,インタフェース型宣言の本体全体とする。{
InterfaceMemberDeclarationsopt}
InterfaceMemberDeclarations: InterfaceMemberDeclaration InterfaceMemberDeclarationsInterfaceMemberDeclaration InterfaceMemberDeclaration: ConstantDeclaration AbstractMethodDeclaration
public
とする。これらは,インタフェースもpublic
と宣言されている,及びそのインタフェースを含むパッケージが7.1で記述されるとおりにアクセス可能ならば,そのインタフェースが宣言されているパッケージ外でアクセス可能とする。
インタフェースは,そのインタフェースが拡張するインタフェースから,そのインタフェースが隠ぺいするフィールド及び上書きするメソッドを除いたすべてのメンバを継承する。
ConstantDeclaration: ConstantModifiersインタフェース本体でのすべてのフィールド宣言は,暗黙的にType
VariableDeclarator ConstantModifiers: one of
public static final
public
,static
及びfinal
とする。書式としてこれらのフィールド修飾子のどれか又はすべてを,冗長だが指定してもよい。ただし,記述しないことが望ましい。
インタフェースにおける定数宣言は,修飾子synchronized
,transient
又はvolatile
のいずれも含んではならない。そうでないときには,コンパイル時エラーを引き起こす。
インタフェースが同じ名前の一つ以上のフィールド(8.3.3.3)を継承するのは可能とする。この状況は,それ自身ではコンパイル時エラーを引き起こさない。しかし,インタフェース本体内で単純名によっていずれかのフィールド参照しようとすると,参照があいまいなため,コンパイル時エラーが発生する。
同じフィールド宣言が,一つのインタフェースから複数の経路で継承されるかもしれない。この状況では,フィールドは1回だけ継承されると考えられ,単純名によってあいまい性なしに参照される。
インタフェースフィールドのための初期化式が単純名によって同じフィールド,又は同じインタフェース内で,ソーステキスト上,後方に宣言されている他のフィールドへの参照を含めば,コンパイル時エラーが発生する。そこで,次の式は,二つのコンパイル時エラーを引き起こす。
interface Test { float f = j; int j = 1; int k = k+1; }これは,
j
が宣言される前にf
の初期化で参照されること,及びk
の初期化がk
そのものを参照していることに基づく。
(ここで微妙なことは,コンパイル時に定数値で初期化されたフィールドが,実行時には最初に初期化される,ということである。これは,クラスのstatic
final
フィールド(8.3.2.1)にも適用される。特にこのことは,たとえ悪意のあるプログラムによっても,これらのフィールドが決してデフォルト初期値(4.5.4)をもたないことを意味する。詳細に関しては,12.4.2及び13.4.8を参照のこと。)
キーワードthis
(15.7.2)又はキーワードsuper
(15.10.2,15.11)がインタフェースのフィールドについての初期化式で出現すれば,コンパイル時エラーが発生する。
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
ではなくて値3
をYELLOW
に与えても,インタフェースLotsOfColors
内のフィールドYELLOW
への参照は,やはりあいまいさをもつ。
前節の例では,フィールドRED
,GREEN
及びBLUE
がインタフェースLotsOfColors
で,インタフェースRainbowColors
及びインタフェースPrintColors
を経由して複数回継承される。しかし,インタフェースLotsOfColors
内でのフィールドRED
への参照は,フィールドRED
の実際の宣言が1回だけなので,あいまいとは考えられない。
AbstractMethodDeclaration: AbstractMethodModifiersoptアクセス修飾子ResultType
MethodDeclarator
Throwsopt
;
AbstractMethodModifiers: AbstractMethodModifier AbstractMethodModifiersAbstractMethodModifier AbstractMethodModifier: one of
public abstract
public
は6.6で記述する。同じ修飾子が抽象メソッド宣言内に複数回現れれば,コンパイル時エラーが発生する。
インタフェース本体内でのすべてのメソッド宣言は,暗黙的にabstract
とする。そこで,その本体は常にセミコロンで表現され,ブロックではない。Javaの旧バージョンとの互換性のために,書式上インタフェース内で宣言されたメソッドに対して冗長に,修飾子abstract
を指定してもよい。ただし,記述しない方が望ましい。
インタフェース本体内でのすべてのメソッド宣言は,暗黙的にpublic
とする。書式上インタフェースメソッドに対して冗長に修飾子public
を指定してもよい。ただし,記述しない方が望ましい。
インタフェースで宣言されたメソッドをstatic
宣言してはならないことに注意すること。そうでないときには,コンパイル時エラーが発生する。これは,Javaにおいてstatic
なメソッドがabstract
であるはずがないからである。
インタフェースで宣言されたメソッドをnative
宣言又はsynchronized
宣言してはならないことに注意すること。そうでないときには,コンパイル時エラーが発生する。これは,それらのキーワードはインタフェースの属性ではなくて実装の属性を記述するからである。しかし,インタフェースで宣言されたメソッドを,インタフェースを実装するクラスでnative
宣言又はsynchronized
宣言されるメソッドで実装してもよい。
インタフェースで宣言されるメソッドをfinal
宣言してはならないことに注意すること。そうでないときには,コンパイル時エラーが発生する。しかし,インタフェースで宣言されるメソッドを,インタフェースを実装するクラスでfinal
宣言されるメソッドで実装してもよい。
インタフェース内でのメソッド宣言が,他のインタフェース内でのメソッドの宣言を上書きする場合,各々のメソッドで異なった返却値の型をもつ,又は一つが返却値の型をもち他方が void
ならば,コンパイル時エラーが発生する。さらにメソッド宣言は,それが上書きするいかなるメソッド宣言とも矛盾するthrows
節(8.4.4)をもってはならない。そうでないときには,コンパイル時エラーが発生する。
メソッドは,シグネチャ単位で上書きされる。例えば,もしインタフェースが同じ名前の二つのpublic
なメソッドを宣言し,しかもサブインタフェースがそれらの一つを上書きすれば,そのサブインタフェースのもう一つのメソッドも継承する。
インタフェースは,インタフェース内での宣言によって上書きされないスーパインタフェースのすべてのメソッドを,その直接的スーパインタフェースから継承する。
インタフェースが,同じシグネチャ(8.4.2)の複数のメソッドを継承することは可能とする。この状況は,そのままではコンパイル時エラーを引き起こさない。インタフェースはすべてのメソッドを継承する。しかし,その継承された任意の二つのメソッドに対して,それらが違った返却値の型をもつか,又は一つが返却値の型をもち他方がvoid
ならば,コンパイル時エラーが発生する。(throws
節は,この場合エラーを引き起こさない)。
同じメソッド宣言が一つのインタフェースから継承される経路は,複数存在することがある。この事実は,いかなる困難も引き起こさず,決してそのままではコンパイル時エラーを生じない。
throws
節の間には,要求される関係は存在しない。
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 }
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
を実装するいかなるクラスも,三つのメソッドシグネチャすべての実装を提供しなければならない。