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

13. バイナリの互換性
Binary Compatibility

Javaプログラム言語のための開発ツールは,ソースコードが利用できる場合にはいつでも,必要に応じて自動再コンパイルをサポートすることが望ましい。型のソース及びバイナリを版管理データベースに記憶しておき,型のバイナリ互換な版をクライアントに提供することで,リンクエラーを防止するためにそのデータベースの完全性機構を利用したClassLoaderを実装してもよい 。

Development tools for the Java programming language should support automatic recompilation as necessary whenever source code is available. Particular implementations may also store the source and binary of types in a versioning database and implement a ClassLoader that uses integrity mechanisms of the database to prevent linkage errors by providing binary-compatible versions of types to clients.

広く配布されることが望ましいパッケージ及びクラスの開発者は,さらに別の問題に直面する。広域分散システムの格好な例であるインターネットにおいては,変更対象の型に直接的に又は間接的に依存する既存のバイナリを自動的に再コンパイルすることは,実用的でなかったり不可能であったりすることが多い。その代わりに,この規定では,既存のバイナリとの互換性を維持する(損なわない)限り,パッケージに対して,又はクラス型若しくはインタフェース型に対して,開発者が行なってもよい変更の集合を定義する。

Developers of packages and classes that are to be widely distributed face a different set of problems. In the Internet, which is our favorite example of a widely distributed system, it is often impractical or impossible to automatically recompile the pre-existing binaries that directly or indirectly depend on a type that is to be changed. Instead, this specification defines a set of changes that developers are permitted to make to a package or to a class or interface type while preserving (not breaking) compatibility with existing binaries.

これらのことは,ACM SIGPLAN Notices, Volume 30, Number 10, October 1995として発行されたProceedings of OOPSLA '95の426ページ〜438ページにあるIra R. Forman, Michael H. Conner, Scott H. Danforth及びLarry K. Raperらの論文Release-to-Release Binary Compatibility in SOMに示されている。その論文の枠組み内で,Javaプログラム言語のバイナリは,(インスタンス変数の追加に関するある条件付きで)論文の著者が識別するすべての意味のある変換のもとでのバイナリ互換性とする。この方式を使用して,Javaプログラム言語がサポートする幾つかの重要なバイナリ互換な変更の一覧を,次に示す。

The paper quoted above appears in Proceedings of OOPSLA '95, published as ACM SIGPLAN Notices, Volume 30, Number 10, October 1995, pages 426-438. Within the framework of that paper, Java programming language binaries are binary compatible under all relevant transformations that the authors identify (with some caveats with respect to the addition of instance variables). Using their scheme, here is a list of some important binary compatible changes that the Java programming language supports:

13.では,すべての実装によって保証されるバイナリ互換性について最小限の規定を示す。Javaプログラム言語は,互換性のあるソースからのものか不明なクラス及びインタフェースのバイナリが混在しているが,それらのソースが13.で示す互換性のある方法で修正されている場合には,互換性を保証する。ただし,アプリケーションの版の間の互換性を対象にしている点に注意すること。Javaプラットフォームの版の間の互換性については,13.の適用範囲外とする。
This chapter specifies minimum standards for binary compatibility guaranteed by all implementations. The Java programming language guarantees compatibility when binaries of classes and interfaces are mixed that are not known to be from compatible sources, but whose sources have been modified in the compatible ways described here. Note that we are discussing compatibility between releases of an application. A discussion of compatibility among releases of the Java platform beyond the scope of this chapter.

開発システムは,再コンパイルできない既存のバイナリに与える変更の影響を,開発者に警告する機能を提供するのが望ましい。

We encourage development systems to provide facilities that alert developers to the impact of changes on pre-existing binaries that cannot be recompiled.

13.では,まず,Javaプログラム言語のためのあらゆるバイナリ形式が備えなければならない特性を規定する(13.1)。次に,バイナリの互換性を,それが何であって何でないのかを示しながら定義する(13.2)。最後に,パッケージ(13.3),クラス(13.4)及びインタフェース(13.5)に対して可能な多くの変更を,これら変更のどれがバイナリ互換性の維持のために保証され,どれが保証されないかを規定しながら列挙する。

This chapter first specifies some properties that any binary format for the Java programming language must have (§13.1). It next defines binary compatibility, explaining what it is and what it is not (§13.2). It finally enumerates a large set of possible changes to packages (§13.3), classes (§13.4) and interfaces (§13.5), specifying which of these changes are guaranteed to preserve binary compatibility and which are not.

13.1 バイナリの形式
The Form of a Binary

プログラムは,The Java Virtual Machine Specification, Second Editionが規定するclassファイルの形式に,又はJavaプログラム言語で記述されたクラスローダが対応付けることができる表現に,コンパイルされなければならない。さらに,結果として生ずるclassファイルは,幾つかの特性をもたなければならない。これら特性の多くは,バイナリの互換性を保存するソースコード変換をサポートするために,選択されたものとする。
Programs must be compiled either into the class file format specified by the The Java Virtual Machine Specification, Second Edition, or into a representation that can be mapped into that format by a class loader written in the Java programming language. Furthermore, the resulting class file must have certain properties. A number of these properties are specifically chosen to support source code transformations that preserve binary compatibility.

要求される特性は,次のとおりとする。

The required properties are:

クラス又はインタフェースに対するバイナリ表現は,次のすべても含まなければならない。
A binary representation for a class or interface must also contain all of the following:

以降の節では,既存のバイナリとの互換性を損なうことなく,クラス及びインタフェースの型の宣言に行ってもよい変更について検討する。13.1で示した変換要件の下で,Java仮想計算機及びそのclassファイルフォーマットは,これら変更をサポートする。変換要件の下でクラスローダがクラスファイルに逆写像する圧縮された表現又は暗号化された表現などの,他の妥当なバイナリフォーマットも,必然的に,これら変更をサポートすることになる。
The following sections discuss changes that may be made to class and interface type declarations without breaking compatibility with pre-existing binaries. Under the translation requirements given above, the Java virtual machine and its class file format support these changes. Any other valid binary format, such as a compressed or encrypted representation that is mapped back into class files by a class loader under the above requirements will necessarily support these changes as well.

13.2 バイナリ互換性の有無
What Binary Compatibility Is and Is Not

型の変更は,エラー無しにリンクされていた既存のバイナリが引き続きエラー無しにリンクされる場合に,既存のバイナリと バイナリ互換(binary compatible) ( バイナリ互換性を損なう(break binary compatibility) ことはないと等価)とする。
A change to a type is binary compatible with (equivalently, does not break binary compatibility with) preexisting binaries if preexisting binaries that previously linked without error will continue to link without error.

バイナリは,他のクラス及びインタフェースのアクセス可能なメンバ及びコンストラクタに依存してコンパイルされる。バイナリ互換性を保存するために,クラス又はインタフェースは,そのアクセス可能なメンバ及びコンストラクタ,並びにそれらの存在及び振る舞いを,その利用者との 取決め(contract) として取り扱うことが望ましい。

Binaries are compiled to rely on the accessible members and constructors of other classes and interfaces. To preserve binary compatibility, a class or interface should treat its accessible members and constructors, their existence and behavior, as a contract with its users.

Javaプログラム言語は,取決めへの追加及び偶然による名前の衝突が,バイナリ互換性を損なうことを防止する設計がなされている。特に,次のとおりとする。

The Java programming language is designed to prevent additions to contracts and accidental name collisions from breaking binary compatibility; specifically:

バイナリ互換性は,ソース互換性と同じではない。特に,13.4.5の例は,すべてを一緒にはコンパイルしないソースから,互換性があるバイナリの集合を生成可能なことを示している。この例は,典型的なものである。すなわち,新しい宣言が追加され,ソースコードの変更されない部分の名前の意味が変わるが,その一方で,ソースコードの変更されていない部分に対する既存のバイナリは,その名前の完全限定された以前のままの意味を保持している。ソースコードの整合性のある集合を生成するには,以前の意味に対応する限定名又はフィールドアクセス式を与えることが要求される。
Binary compatibility is not the same as source compatibility. In particular, the example in §13.4.5 shows that a set of compatible binaries can be produced from sources that will not compile all together. This example is typical: a new declaration is added, changing the meaning of a name in an unchanged part of the source code, while the preexisting binary for that unchanged part of the source code retains the fully-qualified, previous meaning of the name. Producing a consistent set of source code requires providing a qualified name or field access expression corresponding to the previous meaning.

13.3 パッケージの機能変更
Evolution of Packages

新しい最上位のクラス又はインタフェースの型は,その新しい型が関係のない型に既に与えられている名前を再利用しないという条件の下では,既存のバイナリとの互換性を損なわずに,パッケージに追加できる。新しい型が関係のない型に既に与えられている名前を再利用する場合には,それら両方の型のバイナリは同じクラスローダによってロードできないので,衝突が生ずる可能性がある。
A new top-level class or interface type may be added to a package without breaking compatibility with pre-existing binaries, provided the new type does not reuse a name previously given to an unrelated type. If a new type reuses a name previously given to an unrelated type, then a conflict may result, since binaries for both types could not be loaded by the same class loader.

それ自体が,publicではなく,あるpublic型の上位クラス又は上位インタフェースでもない最上位のクラス及びインタフェースの型における変更は,それらを宣言しているパッケージ内の型だけに影響を及ぼす。それらの型は,そのパッケージの影響を受けるバイナリを一緒に更新するという条件の下では,たとえ非互換性がここに記述されていても,削除するか,そうでない場合には変更してよい。

Changes in top-level class and interface types that are not public and that are not a superclass or superinterface, respectively, of a public type, affect only types within the package in which they are declared. Such types may be deleted or otherwise changed, even if incompatibilities are otherwise described here, provided that the affected binaries of that package are updated together.

13.4 クラスの機能変更
Evolution of Classes

13.4では,クラス並びにそのクラスのメンバ及びコンストラクタの宣言の変更が既存のバイナリへ及ぼす影響について示す。
This section describes the effects of changes to the declaration of a class and its members and constructors on pre-existing binaries.

13.4.1 abstractクラス
abstract Classes

abstractと宣言していなかったクラスを,abstractと宣言するように変更する場合,そのクラスの新しいインスタンスを生成しようとする既存のバイナリは,リンク時にInstantiationErrorを投げるか,又は(自己反映メソッドを使用する場合)実行時にInstantiationExceptionを投げる。したがって,広く配布されるクラスに対しては,こうした変更はしないほうがよい。
If a class that was not abstract is changed to be declared abstract, then pre-existing binaries that attempt to create new instances of that class will throw either an InstantiationError at link time, or (if a reflective method is used) an InstantiationException at run time; such a change is therefore not recommended for widely distributed classes.

abstractと宣言していたクラスを,もはやabstractと宣言しないように変更することは,既存のバイナリとの互換性を損なわない。

Changing a class that was declared abstract to no longer be declared abstract does not break compatibility with pre-existing binaries.

13.4.2 finalクラス
final Classes

finalと宣言していなかったクラスを,finalと宣言するように変更する場合,このクラスの既存の下位クラスのバイナリをロードするとき,VerifyErrorが投げられる。これは,finalクラスは下位クラスをもつことができないことによる。広く配布されるクラスに対しては,こうした変更はしないほうがよい。
If a class that was not declared final is changed to be declared final, then a VerifyError is thrown if a binary of a pre-existing subclass of this class is loaded, because final classes can have no subclasses; such a change is not recommended for widely distributed classes.

finalと宣言していたクラスを,もはやfinalと宣言しないように変更することは,既存のバイナリとの互換性を損なわない。

Changing a class that was declared final to no longer be declared final does not break compatibility with pre-existing binaries.

13.4.3 publicクラス
public Classes

publicと宣言していなかったクラスを,publicと宣言するように変更することは,既存のバイナリとの互換性を損なわない。
Changing a class that was not declared public to be declared public does not break compatibility with pre-existing binaries.

publicと宣言していたクラスを,publicと宣言しないように変更する場合,そのクラス型へのアクセスが必要だがもはやアクセスできない既存のバイナリをリンクすると,IllegalAccessErrorが投げられる。広く配布されるクラスに対しては,こうした変更はしないほうがよい。

If a class that was declared public is changed to not be declared public, then an IllegalAccessError is thrown if a pre-existing binary is linked that needs but no longer has access to the class type; such a change is not recommended for widely distributed classes.

13.4.4 上位クラス及び上位インタフェース
Superclasses and Superinterfaces

クラスがそれ自体の上位クラスとなる場合,ロード時にClassCircularityErrorが投げられる。新しくコンパイルしたバイナリを既存のバイナリと共にロードするときに,この循環を生ずる可能性のあるクラス階層へと変更することは,広く配布されるクラスに対しては,しないほうがよい。
A ClassCircularityError is thrown at load time if a class would be a superclass of itself. Changes to the class hierarchy that could result in such a circularity when newly compiled binaries are loaded with pre-existing binaries are not recommended for widely distributed classes.

クラス型の上位クラス又は上位インタフェースの全体集合がメンバを失わないという条件の下では,そのクラス型の直接的上位クラス又は直接的上位インタフェースの集合へ変更を加えても,既存のバイナリとの互換性を損なわない。

Changing the direct superclass or the set of direct superinterfaces of a class type will not break compatibility with pre-existing binaries, provided that the total set of superclasses or superinterfaces, respectively, of the class type loses no members.

直接的上位インタフェースの集合又は直接的上位クラスへの変更によって,どれかのクラス又はインタフェースが,もはや上位クラス又は上位インタフェースでなくなるなら,既存のバイナリをこの修正されたクラスのバイナリと共にロードするときに,リンク時エラーが生ずるかもしれない。広く配布されるクラスに対しては,こうした変更はしないほうがよい。

If a change to the direct superclass or the set of direct superinterfaces results in any class or interface no longer being a superclass or superinterface, respectively, then link-time errors may result if pre-existing binaries are loaded with the binary of the modified class. Such changes are not recommended for widely distributed classes.

例えば,次のテストプログラムを仮定する。

For example, suppose that the following test program:

class Hyper { char h = 'h'; } 
class Super extends Hyper { char s = 's'; }
class Test extends Super {
    public static void main(String[] args) {
        Hyper h = new Super();
        System.out.println(h.h);
    }
}
これをコンパイルし実行すると,次の出力を生成する。
is compiled and executed, producing the output:

h
次に,クラスSuperの新しい版をコンパイルすると仮定する。
Suppose that a new version of class Super is then compiled:

class Super { char s = 's'; }
クラスSuperのこの版は,Hyperの下位クラスではない。次にHyper及びTestの既存のバイナリを,Superの新しい版と共に実行すると,リンク時に,VerifyErrorが投げられる。Superは,Hyperの下位クラスでないので,new Super()の結果は,型Hyperの変数に代入できず,検証器はそれを受け付けない。
This version of class Super is not a subclass of Hyper. If we then run the existing binaries of Hyper and Test with the new version of Super, then a VerifyError is thrown at link time. The verifier objects because the result of new Super() cannot be assigned to a variable of type Hyper, because Super is not a subclass of Hyper.

検証段階がないと何が起こるかを検討することは例として価値がある。この場合,このプログラムを実行すると次の結果を出力する。

It is instructive to consider what might happen without the verification step: the program might run and print:

s
これは,個々のバイナリファイルが正しいJavaコンパイラによって生成されても,検証器なしでは,不整合なバイナリファイルをリンクすることによって型システムが崩れることを示す。
This demonstrates that without the verifier the type system could be defeated by linking inconsistent binary files, even though each was produced by a correct Java compiler.

検証器を欠いている,又は検証器を使うことに失敗している実装は,型の安全性を維持せず,したがって,妥当な実装ではない。

The lesson is that an implementation that lacks a verifier or fails to use it will not maintain type safety and is, therefore, not a valid implementation.

13.4.5 クラス本体及びメンバ宣言
Class Body and Member Declarations

既存のバイナリとの互換性は,上位クラス又は下位クラスのインスタンスメンバ(及びstaticメンバ)と同じである,名前及びアクセス可能性(これらはフィールドに対する場合),又は名前,アクセス可能性,シグネチャ及び返却値型(これらはメソッドに対する場合)をもつインスタンスメンバ(及びstaticメンバ)を追加することによって損なわれることはない。リンクされるクラスの集合がコンパイル時エラーに出会うような場合でも,(実行時には)エラーは発生しない。
No incompatibility with pre-existing binaries is caused by adding an instance (respectively static) member that has the same name, accessibility, (for fields) or same name, accessibility, signature, and return type (for methods) as an instance (respectively static) member of a superclass or subclass. No error occurs even if the set of classes being linked would encounter a compile-time error.

privateと宣言されていないクラスメンバ又はコンストラクタの削除は,そのメンバ又はコンストラクタを既存のバイナリが使用する場合には,リンクエラーを引き起こすかもしれない。

Deleting a class member or constructor that is not declared private may cause a linkage error if the member or constructor is used by a pre-existing binary.

次に例を示す。

If the program:

class Hyper {
	void hello() { System.out.println("hello from Hyper"); }
}
class Super extends Hyper {
	void hello() { System.out.println("hello from Super"); }
}
class Test {
	public static void main(String[] args) {
		new Super().hello();
	}
}
このプログラムをコンパイルし実行すると,次の出力を得る。
is compiled and executed, it produces the output:

hello from Super
クラスSuperの新しい版が生成されたと仮定する。
Suppose that a new version of class Super is produced:

class Super extends Hyper { }
Superを再コンパイルし,この新しいバイナリをTest及びHyperの元のバイナリと共に実行すると次の出力を得る。
then recompiling Super and executing this new binary with the original binaries for Test and Hyper produces the output:

hello from Hyper
これは期待どおりの結果である。
as expected.

superというキーワードは,現在のクラスの中で宣言されたメソッドをう(迂)回し,上位クラスの中で宣言されたメソッドにアクセスするために使用できる。次に式の例を示す。

The super keyword can be used to access a method declared in a superclass, bypassing any methods declared in the current class. The expression:

super.Identifier
この式は,コンパイル時に,上位クラス S の中のメソッド M に解決される。メソッド M がインスタンスメソッドの場合,実行時に呼び出されるメソッド MR は,superを含む式を含むクラスの直接的上位クラスのメンバ M と同じシグネチャをもつメソッドとなる。次にプログラムの例を示す。
is resolved, at compile time, to a method M in the superclass S. If the method M is an instance method, then the method MR invoked at run time is the method with the same signature as M that is a member of the direct superclass of the class containing the expression involving super. Thus, if the program:

class Hyper {
	void hello() { System.out.println("hello from Hyper"); }
}
class Super extends Hyper { }
class Test extends Super {
	public static void main(String[] args) {
		new Test().hello();
	}
	void hello() {
		super.hello();
	}
}
このプログラムをコンパイルし実行すると,次の出力を得る。
is compiled and executed, it produces the output:

hello from Hyper
クラスSuperの次の新しい版を生成すると仮定する。
Suppose that a new version of class Super is produced:

class Super extends Hyper {
	void hello() { System.out.println("hello from Super"); }
}
Super及びHyperを再コンパイルし,Testを再コンパイルしない場合,新しい(再コンパイルされた)バイナリをTestの既存のバイナリと共に実行すると,次の出力を得る。
If Super and Hyper are recompiled but not Test, then running the new binaries with the existing binary of Test produces the output:

hello from Super
これは,予想どおりといってよいかもしれない。(初期の実装の中には欠陥のために,次の出力を得ることがあった。
as you might expect. (A flaw in some early implementations caused them to print:

hello from Hyper
これは正しくない。)
incorrectly.)

13.4.6 メンバ及びコンストラクタへのアクセス
Access to Members and Constructors

メンバ又はコンストラクタのアクセス宣言を,アクセス制限を許すように変更することは,既存のバイナリとの互換性を損ない,バイナリを記号解決するときにリンクエラーを投げる可能性がある。アクセス制限を許すのは,アクセス修飾子を,デフォルトアクセスからprivateアクセスへ,protectedアクセスからデフォルトアクセス若しくはprivateアクセスへ,又はpublicアクセスからprotectedアクセス,デフォルトアクセス若しくはprivateアクセスへ変更する場合とする。したがって,アクセス制限を許すメンバ又はコンストラクタの変更は,広く配布するクラスに対してしないほうがよい。
Changing the declared access of a member or constructor to permit less access may break compatibility with pre-existing binaries, causing a linkage error to be thrown when these binaries are resolved. Less access is permitted if the access modifier is changed from default access to private access; from protected access to default or private access; or from public access to protected, default, or private access. Changing a member or constructor to permit less access is therefore not recommended for widely distributed classes.

バイナリ形式は,メンバ又はコンストラクタをよりアクセス可能とする変更が,下位クラスが(既に)アクセス制限メソッドを定義している場合にはリンクエラーを生じないように定義されている。

Perhaps surprisingly, the binary format is defined so that changing a member or constructor to be more accessible does not cause a linkage error when a subclass (already) defines a method to have less access.

そこで,例えば,パッケージpointsがクラスPointを定義する場合を検討する。

So, for example, if the package points defines the class Point:

package points;
public class Point {
	public int x, y;
	protected void print() {
		System.out.println("(" + x + "," + y + ")");
	}
}
これを次のプログラムTestで使用する。
used by the Test program:

class Test extends points.Point {
	protected void print() { System.out.println("Test"); }
	public static void main(String[] args) {
		Test t = new Test();
		t.print();
	}
}
これらのクラスをコンパイルしTestを実行すると,次の出力を得る。
then these classes compile and Test executes to produce the output:

Test
クラスPoint内のメソッドprintpublicに変更し,クラスPointだけを再コンパイルし,Testの既存のバイナリと共に実行する場合には,コンパイル時にpublicなメソッドをprotectedなメソッドで上書きするのは不適当だが,リンクエラーは発生しない。(これは,printpublicに変更しない限り,新しいクラスPointを使用してクラスTestを再コンパイルすることはできない,という事実による。)
If the method print in class Point is changed to be public, and then only the Point class is recompiled, and then executed with the previously existing binary for Test then no linkage error occurs, even though it is improper, at compile time, for a public method to be overridden by a protected method (as shown by the fact that the class Test could not be recompiled using this new Point class unless print were changed to be public.)

既存の下位クラスのバイナリを損なわずに,上位クラスがprotectedなメソッドをpublicなメソッドに変更することを許していることで,バイナリをより壊れにくくしている。別の方法,すなわち,その変更がリンクエラーを引き起こす場合には,その方法は,付加的なバイナリ非互換性を生み出すことになる。

Allowing superclasses to change protected methods to be public without breaking binaries of preexisting subclasses helps make binaries less fragile. The alternative, where such a change would cause a linkage error, would create additional binary incompatibilities.

13.4.7 フィールド宣言
Field Declarations

広く配布されるプログラムは,そのクライアントにいかなるフィールドも開示しないほうがよい。このことは,以降で議論されるバイナリ互換性の問題とは別に,一般にソフトウェア工学上の良い実践である。クラスへのフィールドの追加は,再コンパイルしない既存のバイナリとの互換性を損うことがある。
Widely distributed programs should not expose any fields to their clients. Apart from the binary compatibility issues discussed below, this is generally good software engineering practice. Adding a field to a class may break compatibility with pre-existing binaries that are not recompiled.

フィールド f を型 T で限定して参照する場合を検討する。さらに,f は,実際に T の上位クラス S で宣言されたインスタンスフィールド(staticなフィールド)であって,f の型が X とする。f と同じ名前をもち,型が X の新しいフィールドを T の上位クラスである S 又は T それ自体の下位クラスに追加する場合,リンクエラーが発生する可能性がある。こうしたリンクエラーは,今示した場合に加えて,次の条件のいずれか一つが成立する場合にだけ発生する。

Assume a reference to a field f with qualifying type T. Assume further that f is in fact an instance (respectively static) field declared in a superclass of T, S, and that the type of f is X. If a new field of type X with the same name as f is added to a subclass of S that is a superclass of T or T itself, then a linkage error may occur. Such a linkage error will occur only if, in addition to the above, either one of the following conditions hold:

特に,フィールドアクセスが,非互換な型をもつ上位クラスのフィールドを以前は参照していたためにクラスがもはや再コンパイルできない場合には,リンクエラーが発生しない。その参照をもつ以前にコンパイルされたクラスは,上位クラスで宣言されたフィールドを参照し続ける。
In particular, no linkage error will occur in the case where a class could no longer be recompiled because a field access previously referenced a field of a superclass with an incompatible type. The previously compiled class with such a reference will continue to reference the field declared in a superclass.

次のコードをコンパイルし実行する場合を,例として示す。

Thus compiling and executing the code:

class Hyper { String h = "hyper"; }
class Super extends Hyper { String s = "super"; }
class Test {
	public static void main(String[] args) {
		System.out.println(new Super().h);
	}
}
これは次の出力を生成する。
produces the output:

hyper
Superの定義を次のとおりに変更する。
Changing Super to be defined as:

class Super extends Hyper {
	String s = "super";
	int h = 0;
}
Hyper及びSuperを再コンパイルし,その結果の新しいバイナリを Testの古いバイナリと一緒に実行すると,次の出力を得る。
recompiling Hyper and Super, and executing the resulting new binaries with the old binary of Test produces the output:

hyper
Hyperのフィールドhは,mainの元々のバイナリによる出力になっている。これは,最初意外なことと思うかもしれないが,実行時に発生する非互換性の数を減らすのに有用である。(理想的には,その意外性を排除するために,再コンパイルが必要なすべてのソースファイルは,その一つでも変更されたときにはいつでも,再コンパイルするのがよい。しかし,特に,インターネットにおいていえるが,それらの膨大な再コンパイルは,実用的ではないか,又は不可能なことが多い。さらに,以前に示したとおり,それら再コンパイルは,ソースファイルの更なる変更を要求することもある。)
The field h of Hyper is output by the original binary of main. While this may seem surprising at first, it serves to reduce the number of incompatibilities that occur at run time. (In an ideal world, all source files that needed recompilation would be recompiled whenever any one of them changed, eliminating such surprises. But such a mass recompilation is often impractical or impossible, especially in the Internet. And, as was previously noted, such recompilation would sometimes require further changes to the source code.)

例として,次のプログラムを検討する。

As an example, if the program:

class Hyper { String h = "Hyper"; }
class Super extends Hyper { }
class Test extends Super {
	public static void main(String[] args) {
		String s = new Test().h;
		System.out.println(s);
	}
}
これをコンパイルし実行すると,次の出力を生成する。
is compiled and executed, it produces the output:

Hyper
クラスSuperの次の新しい版をコンパイルすると仮定する。
Suppose that a new version of class Super is then compiled:

class Super extends Hyper { char h = 'h'; }
コンパイル結果のバイナリをHyper及びTestの既存のバイナリと一緒に使用する場合,依然として出力は次となる。
If the resulting binary is used with the existing binaries for Hyper and Test, then the output is still:

Hyper
このことは,これらバイナリに対する次のソースをコンパイルした場合にコンパイル時エラーを生ずるにも拘わらずいえる。
even though compiling the source for these binaries:

class Hyper { String h = "Hyper"; }
class Super extends Hyper { char h = 'h'; }
class Test extends Super {
	public static void main(String[] args) {
		String s = new Test().h;
		System.out.println(s);
	}
}
コンパイル時エラーの理由は,この場合には,mainに対するソースコードのhが,Superで宣言されたcharフィールドを参照するものとして解釈されるが,char値は,Stringに代入できないことによる。
would result in a compile-time error, because the h in the source code for main would now be construed as referring to the char field declared in Super, and a char value can't be assigned to a String.

クラスからフィールドを削除することは,このフィールドを参照する既存のバイナリとの互換性を損ない,既存のバイナリからの参照をリンクする場合には,NoSuchFieldErrorが投げられる。privateなフィールドだけを,広く配布されるクラスから安全に削除してよい。

Deleting a field from a class will break compatibility with any pre-existing binaries that reference this field, and a NoSuchFieldError will be thrown when such a reference from a pre-existing binary is linked. Only private fields may be safely deleted from a widely distributed class.

13.4.8 finalフィールド及び定数
final Fields and Constants

finalでなかったフィールドをfinalに変更する場合,そのフィールドに新しい値を代入しようとする既存のバイナリとの互換性が損なわれる。
If a field that was not final is changed to be final, then it can break compatibility with pre-existing binaries that attempt to assign new values to the field.

次に例を示す。

For example, if the program:

class Super { static char s; }
class Test extends Super {
	public static void main(String[] args) {
		s = 'a';
		System.out.println(s);
	}
}
このプログラムをコンパイルし実行すると,次の出力を得る。
is compiled and executed, it produces the output:

a
クラスSuperの新しい版を作成したと仮定する。
Suppose that a new version of class Super is produced:

class Super { final static char s = 'b'; }
Superを再コンパイルしTestを再コンパイルしない場合に,(Superの)新しいバイナリとTestの既存のバイナリとを一緒に実行すると,IllegalAccessErrorが生ずる。
If Super is recompiled but not Test, then running the new binary with the existing binary of Test results in a IllegalAccessError.

キーワードfinalの削除又はフィールドの初期化値の変更は,既存のバイナリとの互換性を損なわない。

Deleting the keyword final or changing the value to which a field is initialized does not break compatibility with existing binaries.

フィールドがコンパイル時定数の場合には,キーワードfinalの削除又はその値の変更は,既存のバイナリとの互換性を損なわないが,これは,既存のバイナリが(フィールドアクセスを)実行しないことによる。ただし,既存のバイナリは,再コンパイルされない限りその定数に対する新しい値を見ることはない。

If a field is a compile-time constant, then deleting the keyword final or changing its value will not break compatibility with pre-existing binaries by causing them not to run, but they will not see any new value for the constant unless they are recompiled.

次に例を示す。

If the example:

class Flags { final static boolean debug = true; }
class Test {
	public static void main(String[] args) {
		if (Flags.debug)
			System.out.println("debug is true");
	}
}
これをコンパイルし実行すると,次の出力を得る。
is compiled and executed, it produces the output:

debug is true
クラスFlagsの新しい版を作成すると仮定する。
Suppose that a new version of class Flags is produced:

class Flags { final static boolean debug = false; }
Flagsを再コンパイルするがTestは再コンパイルしない場合,(Flagsの)新しいバイナリをTestの既存のバイナリとを一緒に実行すると,次の出力を得る。
If Flags is recompiled but not Test, then running the new binary with the existing binary of Test produces the output:

debug is true
これは,debugの値がコンパイル時定数であって,その値を,クラスFlagsへの参照を行わずにTestのコンパイル時に使用できたことによる。
because the value of debug was a compile-time constant, and could have been used in compiling Test without making a reference to the class Flags.

この結果は,14.20の最後に示したとおり,条件コンパイルをサポートするという決定の副作用である。

This result is a side-effect of the decision to support conditional compilation, as discussed at the end of §14.20.

この振る舞いは,次の修正した例に示すとおり,Flagsをインタフェースに変更しても変わらない。

This behavior would not change if Flags were changed to be an interface, as in the modified example:

interface Flags { boolean debug = true; }
class Test {
	public static void main(String[] args) {
		if (Flags.debug)
			System.out.println("debug is true");
	}
}
(定数をインライン展開とすることを要求する理由の一つは,switch文が各caseで定数を要求し,それら定数値の二つがいずれも同じであってはならないことによる。コンパイラは,コンパイル時に,switch文における重複する定数値を検査する。classファイルフォーマットは,case値の記号的リンクは行わない。)
(One reason for requiring inlining of constants is that switch statements require constants on each case, and no two such constant values may be the same. The compiler checks for duplicate constant values in a switch statement at compile time; the class file format does not do symbolic linkage of case values.)

広く配布されるコードにおいて“不定の定数”にともなう問題を回避する最善の方法として,絶対に変更されそうにない値だけをコンパイル時定数として宣言する。インタフェースの中のコンパイル時定数の多くは,Java言語がサポートしていない列挙型を置き換える小さな整数値とする。これらの小さな値は,任意に選ぶことができ,変更が必要とならないことが望ましい。真の数学的定数は別として,ソースコードでは,static及びfinalとして宣言されたクラス変数は,なるべく使わないことが望ましい。finalの読出し専用の性質が要求される場合には,privateであってstaticな変数と,その値を得るための適切なアクセス用メソッドとを宣言するのを,よりよい選択とする。これを例で示す。

The best way to avoid problems with "inconstant constants" in widely-distributed code is to declare as compile time constants only values which truly are unlikely ever to change. Many compile time constants in interfaces are small integer values replacing enumerated types, which the language does not support; these small values can be chosen arbitrarily, and should not need to be changed. Other than for true mathematical constants, we recommend that source code make very sparing use of class variables that are declared static and final. If the read-only nature of final is required, a better choice is to declare a private static variable and a suitable accessor method to get its value. Thus we recommend:

private static int N;
public static int getN() { return N; }
これは,次よりも望ましい。
rather than:

public static final int N = ...;
Nが読出し専用の必要がない場合には,次で問題はない。
There is no problem with:

public static int N = ...;
一般的な規則として,真に変わらない定数値だけをインタフェースで宣言するのが望ましい。インタフェースのプリミティブ型のフィールドを変更してもよい場合には,その値は,慣用語法的に次のとおりに表現してよいことを注意しておく。ただし,これはしないほうがよい。
if N need not be read-only. We also recommend, as a general rule, that only truly constant values be declared in interfaces. We note, but do not recommend, that if a field of primitive type of an interface may change, its value may be expressed idiomatically as in:

interface Flags {
	boolean debug = new Boolean(true).booleanValue();
}
これによって,その値が定数でないことを保証する。他のプリミティブ型に対しても,同様の慣用語法が存在する。
insuring that this value is not a constant. Similar idioms exist for the other primitive types.

注意するもう一つの点としては,定数値をもつstaticfinalなフィールドは,(プリミティブ型又はString型かどうかによらず,)決してそれ自体の型のデフォルト初期値をもつように見えてはならない(4.5.5)ことがある。これは,それらフィールドのすべては,クラスの初期化中に最初に初期化されるように見えることを意味する(8.3.2.19.3.1及び12.4.2)。

One other thing to note is that static final fields that have constant values (whether of primitive or String type) must never appear to have the default initial value for their type (§4.5.5). This means that all such fields appear to be initialized first during class initialization (§8.3.2.1, §9.3.1, §12.4.2).

13.4.9 staticフィールド
static Fields

privateと宣言されていないフィールドが,staticと宣言されておらずstaticと宣言されるように変更される場合,及びその反対の場合,そのフィールドが,他の種類のフィールドを期待する既存のバイナリによって使用されるときには,リンク時エラー,特に,IncompatibleClassChangeErrorとなる。これらの変更は,広く配布されるコードでは望ましくない。
If a field that is not declared private was not declared static and is changed to be declared static, or vice versa, then a linkage time error, specifically an IncompatibleClassChangeError, will result if the field is used by a preexisting binary which expected a field of the other kind. Such changes are not recommended in code that has been widely distributed.

13.4.10 transientフィールド
transient Fields

フィールドのtransient修飾子の追加又は削除は,既存のバイナリとの互換性を損なわない。
Adding or deleting a transient modifier of a field does not break compatibility with pre-existing binaries.

13.4.11 メソッド宣言及びコンストラクタ宣言
Method and Constructor Declarations

クラスへのメソッド宣言又はコンストラクタ宣言の追加は,いかなる既存のバイナリとの互換性も損なわない。呼出しが,非互換な型をもつ上位クラスのメソッド又はコンストラクタを以前は参照していたために,もはや型を再コンパイルできない場合には,そのような参照をもつ以前にコンパイルしたクラスが,上位クラスで宣言されたメソッド又はコンストラクタを参照し続ける。
Adding a method or constructor declaration to a class will not break compatibility with any pre-existing binaries, in the case where a type could no longer be recompiled because an invocation previously referenced a method or constructor of a superclass with an incompatible type. The previously compiled class with such a reference will continue to reference the method or constructor declared in a superclass.

T の限定をもつメソッド m への参照を検討する。さらに,m が,実際に T の上位クラス S で宣言されたインスタンスメソッド(staticなメソッド)であると仮定する。m と同じシグネチャ及び返却値型をもつ型 X の新しいメソッドが,T の上位クラスである S 又は T それ自体の下位クラスに追加される場合,リンクエラーが発生することがある。そうしたリンクエラーは,今示した場合に加えて,次の条件のいずれか一つが成立する場合にだけ発生する。

Assume a reference to a method m with qualifying type T. Assume further that m is in fact an instance (respectively static) method declared in a superclass of T, S. If a new method of type X with the same signature and return type as m is added to a subclass of S that is a superclass of T or T itself, then a linkage error may occur. Such a linkage error will occur only if, in addition to the above, either one of the following conditions hold:

クラスからのメソッド又はコンストラクタの削除は,このメソッド又はコンストラクタを参照していたあらゆる既存のバイナリとの互換性を損なうことがある。既存のバイナリからの参照をリンクする場合には,NoSuchMethodErrorが投げられる可能性がある。これらエラーは,合致するシグネチャ又は返却値型をもつメソッドが上位クラスで宣言されていない場合にだけ発生する。
Deleting a method or constructor from a class may break compatibility with any pre-existing binary that referenced this method or constructor; a NoSuchMethodError may be thrown when such a reference from a pre-existing binary is linked. Such an error will occur only if no method with a matching signature and return type is declared in a superclass.

クラスのソースコードが宣言されたコンストラクタを含まない場合,Javaコンパイラは,自動的に仮引数をもたないコンストラクタを供給する。それらのクラスのソースコードに,一つ以上のコンストラクタ宣言を追加すると,このデフォルトのコンストラクタが自動的に生成されることを防ぐことができる。これは,実効的には(デフォルト)コンストラクタを削除することを意味する。ただし,新しく作成したコンストラクタの一つが仮引数をもつ場合には,デフォルトコンストラクタを置き換えることになる。自動的に供給される仮引数をもたないコンストラクタには,その宣言のクラスと同じアクセス修飾子を与える。したがって,既存のバイナリとの互換性を維持するほうがよい場合には,あらゆる置換えは,同じ又はより多くのアクセスをもつことが望ましい。

If the source code for a class contains no declared constructors, the Java compiler automatically supplies a constructor with no parameters. Adding one or more constructor declarations to the source code of such a class will prevent this default constructor from being supplied automatically, effectively deleting a constructor, unless one of the new constructors also has no parameters, thus replacing the default constructor. The automatically supplied constructor with no parameters is given the same access modifier as the class of its declaration, so any replacement should have as much or more access if compatibility with pre-existing binaries is to be preserved.

13.4.12 メソッド及びコンストラクタの仮引数
Method and Constructor Parameters

メソッド又はコンストラクタの形式仮引数の名前の変更は,既存のバイナリには影響しない。メソッド名,メソッド若しくはコンストラクタの形式仮引数の型の変更,又はメソッド若しくはコンストラクタの宣言への仮引数の追加若しくは削除は,新しいシグネチャをもつメソッド又はコンストラクタを生成し,古いシグネチャをもつメソッド又はコンストラクタの削除,及び新しいシグネチャをもつメソッド又はコンストラクタの追加を組み合わせた影響をもつ(13.4.11参照)。
Changing the name of a formal parameter of a method or constructor does not impact pre-existing binaries. Changing the name of a method, the type of a formal parameter to a method or constructor, or adding a parameter to or deleting a parameter from a method or constructor declaration creates a method or constructor with a new signature, and has the combined effect of deleting the method or constructor with the old signature and adding a method or constructor with the new signature (see §13.4.11).

13.4.13 メソッドの結果の型
Method Result Type

メソッドの結果の型の変更,結果の型のvoidへの置換え,又はvoidの結果の型への置換えは,古いメソッドの削除,及び新しい結果の型又は新しいvoidの結果をもつ新しいメソッドの追加を組み合わせた影響をもつ(13.4.11参照)。
Changing the result type of a method, replacing a result type with void, or replacing void with a result type has the combined effect of deleting the old method and adding a new method with the new result type or newly void result (see §13.4.11).

13.4.14 abstractメソッド
abstract Methods

abstract宣言をしているメソッドをabstract宣言しないと変更することは,既存のバイナリとの互換性を損なわない。
Changing a method that is declared abstract to no longer be declared abstract does not break compatibility with pre-existing binaries.

abstract宣言をしていないメソッドをabstract宣言すると変更することは,以前にそのメソッドを呼び出していた既存のバイナリとの互換性を損ない,AbstractMethodErrorを引き起こす。

Changing a method that is not declared abstract to be declared abstract will break compatibility with pre-existing binaries that previously invoked the method, causing an AbstractMethodError.

次に例を示す。

If the example program:

class Super { void out() { System.out.println("Out"); } }
class Test extends Super {
	public static void main(String[] args) {
		Test t = new Test();
		System.out.println("Way ");
		t.out();
	}
}
このプログラムをコンパイルし実行すると,次の出力を得る。
is compiled and executed, it produces the output:

Way
Out
クラスSuperの新しい版を作成したと仮定する。
Suppose that a new version of class Super is produced:

abstract class Super {
	abstract void out();
}
Superは再コンパイルするがTestは再コンパイルしない場合,新しいバイナリをTestの既存のバイナリと共に実行すると,AbstractMethodErrorを生ずる。これは,クラスTestは,メソッドoutの実装をもたず,そのため抽象的となる(又は抽象的となるのが望ましい)ことによる。
If Super is recompiled but not Test, then running the new binary with the existing binary of Test results in a AbstractMethodError, because class Test has no implementation of the method out, and is therefore is (or should be) abstract.

13.4.15 finalメソッド
final Methods

finalでないインスタンスメソッドをfinalに変更することは,メソッドの上書きが可能なことに依存する既存のバイナリとの互換性を損なうことがある。
Changing an instance method that is not final to be final may break compatibility with existing binaries that depend on the ability to override the method.

次に例を示す。

If the test program:

class Super { void out() { System.out.println("out"); } }
class Test extends Super {
	public static void main(String[] args) {
		Test t = new Test();
		t.out();
	}
	void out() { super.out(); }
}
このプログラムをコンパイルし実行すると,次の出力を得る。
is compiled and executed, it produces the output:

out
クラスSuperの新しい版を作成したと仮定する。
Suppose that a new version of class Super is produced:

class Super { final void out() { System.out.println("!"); } }
Superは再コンパイルするがTestは再コンパイルしない場合,新しいバイナリをTestの既存のバイナリとともに実行すると,VerifyErrorを生ずる。これは,クラスTestは,インスタンスメソッドoutを不適切に上書きしようと試みたことによる。
If Super is recompiled but not Test, then running the new binary with the existing binary of Test results in a VerifyError because the class Test improperly tries to override the instance method out.

finalでないクラスメソッド(すなわち,staticメソッド)をfinalに変更することは,既存のバイナリとの互換性を損なわない。これは,メソッドが上書きされることは可能ではなかったことによる。

Changing a class (static) method that is not final to be final does not break compatibility with existing binaries, because the method could not have been overridden.

メソッドからfinal修飾子を削除することは,既存のバイナリとの互換性を損なわない。

Removing the final modifier from a method does not break compatibility with pre-existing binaries.

13.4.16 nativeメソッド
native Methods

メソッドのnative修飾子を追加又は削除することは,既存のバイナリとの互換性を損なわない。
Adding or deleting a native modifier of a method does not break compatibility with pre-existing binaries.

再コンパイルしていない既存のnativeメソッドに関する型への変更の影響は,この規定の適用範囲外とし,実装の記述で提供されることが望ましい。実装処理系は,その影響を制限する方法で,nativeメソッドを実装することが望ましいが,必須ではない。

The impact of changes to types on preexisting native methods that are not recompiled is beyond the scope of this specification and should be provided with the description of an implementation. Implementations are encouraged, but not required, to implement native methods in a way that limits such impact.

13.4.17 staticメソッド
static Methods

private宣言していないメソッドがstatic宣言されていた(すなわち,クラスメソッドであった)場合であって,それを,static宣言しない(すなわち,インスタンスメソッドとする)に変更する場合,又はその逆の場合,既存のバイナリとの互換性は損なわれる可能性があり,これらのメソッドを既存のバイナリとともに使用すると,リンク時エラー,IncompatibleClassChangeErrorとなる。広く配布されているコードに対しては,それらの変更はしないほうがよい。
If a method that is not declared private was declared static (that is, a class method) and is changed to not be declared static (that is, to an instance method), or vice versa, then compatibility with pre-existing binaries may be broken, resulting in a linkage time error, namely an IncompatibleClassChangeError, if these methods are used by the pre-existing binaries. Such changes are not recommended in code that has been widely distributed.

13.4.18 synchronizedメソッド
synchronized Methods

メソッドのsynchronized修飾子を追加又は削除することは,既存のバイナリとの互換性を損なわない。
Adding or deleting a synchronized modifier of a method does not break compatibility with existing binaries.

13.4.19 メソッド及びコンストラクタのthrows
Method and Constructor Throws

メソッド又はコンストラクタのthrows節の変更は,既存のバイナリとの互換性を損なわない。この節は,コンパイル時にだけ検査される。
Changes to the throws clause of methods or constructors do not break compatibility with existing binaries; these clauses are checked only at compile time.

13.4.20 メソッド及びコンストラクタ本体
Method and Constructor Body

メソッド又はコンストラクタの本体の変更は,既存のバイナリとの互換性を損なわない。
Changes to the body of a method or constructor do not break compatibility with pre-existing binaries.

コンパイラは,コンパイル時にメソッドをインライン展開できないことに注意すること。

We note that a compiler cannot expand a method inline at compile time.

メソッドのキーワードfinalは,メソッドが安全にインライン展開できるという意味ではない。それは,単にそのメソッドが上書きできないことだけを意味する。そのメソッドの新しい版をリンク時に提供することは依然として可能とする。さらに,元のプログラムの構造は,自己反映性の目的のために保存されなければならない。

The keyword final on a method does not mean that the method can be safely inlined; it means only that the method cannot be overridden. It is still possible that a new version of that method will be provided at link time. Furthermore, the structure of the original program must be preserved for purposes of reflection.

一般に,実装は,遅延束縛の(実行時の)コード生成及び最適化を使用するほうがよい。

In general we suggest that implementations use late-bound (run-time) code generation and optimization.

13.4.21 メソッド及びコンストラクタのオーバロード
Method and Constructor Overloading

既存のメソッド又はコンストラクタをオーバロードする新しいメソッド又はコンストラクタの追加は,既存のバイナリとの互換性を損なわない。各々の呼出しのために使用するシグネチャは,これらの既存のバイナリがコンパイルされた時に決定される。したがって,それらのシグネチャが,両方とも適用可能であって,最初に選択したシグネチャよりも的確な場合であっても,新しく追加されたメソッド又はコンストラクタは使用されない。
Adding new methods or constructors that overload existing methods or constructors does not break compatibility with pre-existing binaries. The signature to be used for each invocation was determined when these existing binaries were compiled; therefore newly added methods or constructors will not be used, even if their signatures are both applicable and more specific than the signature originally chosen.

新しくオーバロードされたメソッド又はコンストラクタを追加することは,そのクラス又はインタフェースを次にコンパイルする時に,コンパイル時エラーとなる可能性がある。これは,最も特殊なメソッド又はコンストラクタが存在しないことによる(15.12.2.2)。その一方で,プログラムが実行された時には,それらのエラーは発生しない。これは,オーバロードの解決は,実行時には行われないことによる。

While adding a new overloaded method or constructor may cause a compile-time error the next time a class or interface is compiled because there is no method or constructor that is most specific (§15.12.2.2), no such error occurs when a program is executed, because no overload resolution is done at execution time.

次に例を示す。

If the example program:

class Super {
	static void out(float f) { System.out.println("float"); }
}
class Test {
	public static void main(String[] args) {
		Super.out(2);
	}
}
このプログラムをコンパイルし実行すると,次の出力を得る。
is compiled and executed, it produces the output:

float
クラスSuperの新しい版を作成すると仮定する。
Suppose that a new version of class Super is produced:

class Super {
	static void out(float f) { System.out.println("float"); }
	static void out(int i) { System.out.println("int"); }
}
Superを再コンパイルするがTestを再コンパイルしない場合,その新しいバイナリをTestの既存のバイナリと一緒に実行すると,依然として,次の出力を得る。
If Super is recompiled but not Test, then running the new binary with the existing binary of Test still produces the output:

float
しかし,この新しいSuperを使用してTestを再コンパイルする場合には,次の出力を得る。
However, if Test is then recompiled, using this new Super, the output is then:

int
これは,先のプログラムが,素朴に期待していた結果である。
as might have been naively expected in the previous case.

13.4.22 メソッドの上書き
Method Overriding

インスタンスメソッドを下位クラスに追加し,それが上位クラスの中のメソッドを上書きする場合,既存のバイナリにおけるメソッド呼出しは,下位クラスのメソッドを見い出し,これらバイナリは影響を受けない。クラスメソッドをクラスに追加する場合,その参照の限定する型がその下位クラスの型でなければ,このメソッドは発見されない。
If an instance method is added to a subclass and it overrides a method in a superclass, then the subclass method will be found by method invocations in pre-existing binaries, and these binaries are not impacted. If a class method is added to a class, then this method will not be found unless the qualifying type of the reference is the subclass type.

13.4.23 静的初期化子
Static Initializers

クラスの静的初期化子(8.7)の追加,削除,又は変更は,既存のバイナリに影響を与えない。
Adding, deleting, or changing a static initializer (§8.7) of a class does not impact pre-existing binaries.

13.5 インタフェースの機能変更
Evolution of Interfaces

13.5では,インタフェース及びそのメンバの宣言の変更が,既存のバイナリに与える影響を規定する。
This section describes the impact of changes to the declaration of an interface and its members on pre-existing binaries.

13.5.1 publicインタフェース
public Interfaces

public宣言をしていないインタフェースをpublic宣言に変更することは,既存のバイナリとの互換性を損なわない。
Changing an interface that is not declared public to be declared public does not break compatibility with pre-existing binaries.

public宣言をしているインタフェースをpublic宣言をしないと変更した場合,そのインタフェース型を必要とするがもはやアクセスをもたない既存のバイナリをリンクしたとき,IllegalAccessErrorが投げられる。したがって,広く配布されるインタフェースに対しては,それらの変更はしないほうがよい。

If an interface that is declared public is changed to not be declared public, then an IllegalAccessError is thrown if a pre-existing binary is linked that needs but no longer has access to the interface type, so such a change is not recommended for widely distributed interfaces.

13.5.2 上位インタフェース
Superinterfaces

インタフェース階層の変更は,13.4.4で示したとおりの,クラス階層への変更と同じ方法で,エラーを引き起こす。特に,以前はクラスの上位インタフェースであったものをもはや上位インタフェースではないとする変更は,既存のバイナリとの互換性を損なう可能性があって,VerifyErrorを生ずることがある。
Changes to the interface hierarchy cause errors in the same way that changes to the class hierarchy do, as described in §13.4.4. In particular, changes that result in any previous superinterface of a class no longer being a superinterface can break compatibility with pre-existing binaries, resulting in a VerifyError.

13.5.3 インタフェースメンバ
The Interface Members

インタフェースへのメンバの追加は,既存のバイナリとの互換性を損なわない。C の上位インタフェースに追加されたフィールドは,C の上位クラスから継承されたフィールドを隠ぺいすることがある。元の参照がインスタンスフィールドに対してなされていた場合には,IncompatibleClassChangeErrorが生ずる。元の参照が代入であった場合には,IllegalAccessError が生ずる。
Adding a method to an interface does not break compatibility with pre-existing binaries. A field added to a superinterface of C may hide a field inherited from a superclass of C. If the original reference was to an instance field, an IncompatibleClassChangeError will result. If the original reference was an assignment, an IllegalAccessError will result.

インタフェースからのメンバの削除は,既存のバイナリにおいてリンクエラーを引き起こすことがある。

Deleting a member from an interface may cause linkage errors in pre-existing binaries.

次に例を示す。

If the example program:

interface I { void hello(); }
class Test implements I {
	public static void main(String[] args) {
		I anI = new Test();
		anI.hello();
	}
	public void hello() { System.out.println("hello"); }
}
このプログラムをコンパイルし実行すると,次の出力を得る。
is compiled and executed, it produces the output:

hello
インタフェースIの新しい版を作成すると仮定する。
Suppose that a new version of interface I is compiled:

interface I { }
Iを再コンパイルするがTestを再コンパイルしない場合,新しいバイナリをTestの既存のバイナリと一緒に実行すると,NoSuchMethodErrorを生ずる。(初期の実装では,このプログラムは動作することがあった。これは,メソッドhelloがもはやインタフェースIに存在しないという事実が,正しく検知されなかったことによる。)
If I is recompiled but not Test, then running the new binary with the existing binary for Test will result in a NoSuchMethodError. (In some early implementations this program still executed; the fact that the method hello no longer exists in interface I was not correctly detected.)

13.5.4 フィールド宣言
Field Declarations

インタフェースにおいてフィールド宣言を変更するための考慮点は,13.4.7及び13.4.8で示すとおりの,クラスにおけるstatic finalフィールドに対するものと同じとする。
The considerations for changing field declarations in interfaces are the same as those for static final fields in classes, as described in §13.4.7 and §13.4.8.

13.5.5 abstractメソッド宣言
Abstract Method Declarations

インタフェースにおいて抽象メソッド宣言を変更するための考慮点は,13.4.1213.4.1313.4.19及び13.4.21で示すとおりの,クラスにおけるabstractメソッドに対するものと同じとする。
The considerations for changing abstract method declarations in interfaces are the same as those for abstract methods in classes, as described in 13.4.12, 13.4.13, 13.4.19, and 13.4.21.

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