目次 | 前 | 次 | 索引 | Java言語規定 第2版 |
Javaプログラム言語のための開発ツールは,ソースコードが利用できる場合にはいつでも,必要に応じて自動再コンパイルをサポートすることが望ましい。型のソース及びバイナリを版管理データベースに記憶しておき,型のバイナリ互換な版をクライアントに提供することで,リンクエラーを防止するためにそのデータベースの完全性機構を利用したClassLoader
を実装してもよい 。
ClassLoader
that uses integrity mechanisms of the database to prevent linkage errors by providing binary-compatible versions of types to clients.広く配布されることが望ましいパッケージ及びクラスの開発者は,さらに別の問題に直面する。広域分散システムの格好な例であるインターネットにおいては,変更対象の型に直接的に又は間接的に依存する既存のバイナリを自動的に再コンパイルすることは,実用的でなかったり不可能であったりすることが多い。その代わりに,この規定では,既存のバイナリとの互換性を維持する(損なわない)限り,パッケージに対して,又はクラス型若しくはインタフェース型に対して,開発者が行なってもよい変更の集合を定義する。
これらのことは,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プログラム言語がサポートする幾つかの重要なバイナリ互換な変更の一覧を,次に示す。
private
な,フィールド,メソッド又はコンストラクタの削除。
private
fields, methods, or constructors of a class.開発システムは,再コンパイルできない既存のバイナリに与える変更の影響を,開発者に警告する機能を提供するのが望ましい。
13.では,まず,Javaプログラム言語のためのあらゆるバイナリ形式が備えなければならない特性を規定する(13.1)。次に,バイナリの互換性を,それが何であって何でないのかを示しながら定義する(13.2)。最後に,パッケージ(13.3),クラス(13.4)及びインタフェース(13.5)に対して可能な多くの変更を,これら変更のどれがバイナリ互換性の維持のために保証され,どれが保証されないかを規定しながら列挙する。
class
ファイルの形式に,又はJavaプログラム言語で記述されたクラスローダが対応付けることができる表現に,コンパイルされなければならない。さらに,結果として生ずるclass
ファイルは,幾つかの特性をもたなければならない。これら特性の多くは,バイナリの互換性を保存するソースコード変換をサポートするために,選択されたものとする。
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.
super
.f という形式の場合,C の上位クラスを,参照の限定する型とする。
super
.f then the superclass of C is the qualifying type of the reference.final
であってコンパイル時定数式で初期化されるフィールドへの参照は,コンパイル時に,表示された定数値に解決される。このような定数フィールドへの参照は,バイナリファイルの中のコードには存在しないことが望ましい。ただし,定数フィールドを含むクラス又はインタフェースは除く。この場合には,初期化のためのコードが存在する。さらに,定数フィールドは,常に初期化済みで出現しなければならない。すなわち,そのようなフィールドの型に対するデフォルト初期化値は,決して観測されてはならない。詳細は,13.4.8(の最後)を参照すること。
final
and initialized with compile-time constant expressions are resolved at compile time to the constant value that is denoted. No reference to such a constant field should be present in the code in a binary file (except in the class or interface containing the constant field, which will have code to initialize it), and such constant fields must always appear to have been initialized; the default initial value for the type of such a field must never be observed. See §13.4.8 for a discussion.Object
の場合,式の限定する型をObject
とする。そうでない場合には,次のとおりとする。
Object
then the qualifying type of the expression is Object
. Otherwise: super
.m という形式の場合,C の上位クラスを,メソッド呼出しの限定する型とする。
super
.m then the superclass of C is the qualifying type of the method invocation.void
と宣言された値を返却しないことの指示も含まなければならない。メソッドのシグネチャは,次のすべてを含まなければならない。
void
and does not return a value. The signature of a method must include all of the following:new
D(...) 又は X.new D(...) という形式の場合,呼出しの限定する型を,D とする。
new
D(...) or X.new D(...), then the qualifying type of the invocation is D.this
(...) という形式の場合,呼出しの限定する型を,C とする。
this
(...), then the qualifying type of the expression is C.
Object
でない場合,このクラスの直接的上位クラスへの記号参照。
Object
, then a symbolic reference to the direct superclass of this classclass
ファイルフォーマットは,これら変更をサポートする。変換要件の下でクラスローダがクラスファイルに逆写像する圧縮された表現又は暗号化された表現などの,他の妥当なバイナリフォーマットも,必然的に,これら変更をサポートすることになる。
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. バイナリは,他のクラス及びインタフェースのアクセス可能なメンバ及びコンストラクタに依存してコンパイルされる。バイナリ互換性を保存するために,クラス又はインタフェースは,そのアクセス可能なメンバ及びコンストラクタ,並びにそれらの存在及び振る舞いを,その利用者との 取決め(contract) として取り扱うことが望ましい。
Javaプログラム言語は,取決めへの追加及び偶然による名前の衝突が,バイナリ互換性を損なうことを防止する設計がなされている。特に,次のとおりとする。
それ自体が,public
ではなく,あるpublic
型の上位クラス又は上位インタフェースでもない最上位のクラス及びインタフェースの型における変更は,それらを宣言しているパッケージ内の型だけに影響を及ぼす。それらの型は,そのパッケージの影響を受けるバイナリを一緒に更新するという条件の下では,たとえ非互換性がここに記述されていても,削除するか,そうでない場合には変更してよい。
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.abstract
クラス
abstract
Classesabstract
と宣言していなかったクラスを,abstract
と宣言するように変更する場合,そのクラスの新しいインスタンスを生成しようとする既存のバイナリは,リンク時にInstantiationError
を投げるか,又は(自己反映メソッドを使用する場合)実行時にInstantiationException
を投げる。したがって,広く配布されるクラスに対しては,こうした変更はしないほうがよい。
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
と宣言しないように変更することは,既存のバイナリとの互換性を損なわない。
abstract
to no longer be declared abstract
does not break compatibility with pre-existing binaries.final
クラス
final
Classesfinal
と宣言していなかったクラスを,final
と宣言するように変更する場合,このクラスの既存の下位クラスのバイナリをロードするとき,VerifyError
が投げられる。これは,final
クラスは下位クラスをもつことができないことによる。広く配布されるクラスに対しては,こうした変更はしないほうがよい。
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
と宣言しないように変更することは,既存のバイナリとの互換性を損なわない。
final
to no longer be declared final
does not break compatibility with pre-existing binaries.public
クラス
public
Classespublic
と宣言していなかったクラスを,public
と宣言するように変更することは,既存のバイナリとの互換性を損なわない。
public
to be declared public
does not break compatibility with pre-existing binaries.
public
と宣言していたクラスを,public
と宣言しないように変更する場合,そのクラス型へのアクセスが必要だがもはやアクセスできない既存のバイナリをリンクすると,IllegalAccessError
が投げられる。広く配布されるクラスに対しては,こうした変更はしないほうがよい。
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.ClassCircularityError
が投げられる。新しくコンパイルしたバイナリを既存のバイナリと共にロードするときに,この循環を生ずる可能性のあるクラス階層へと変更することは,広く配布されるクラスに対しては,しないほうがよい。
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.クラス型の上位クラス又は上位インタフェースの全体集合がメンバを失わないという条件の下では,そのクラス型の直接的上位クラス又は直接的上位インタフェースの集合へ変更を加えても,既存のバイナリとの互換性を損なわない。
直接的上位インタフェースの集合又は直接的上位クラスへの変更によって,どれかのクラス又はインタフェースが,もはや上位クラス又は上位インタフェースでなくなるなら,既存のバイナリをこの修正されたクラスのバイナリと共にロードするときに,リンク時エラーが生ずるかもしれない。広く配布されるクラスに対しては,こうした変更はしないほうがよい。
これをコンパイルし実行すると,次の出力を生成する。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); } }
次に,クラスh
Super
の新しい版をコンパイルすると仮定する。
Super
is then compiled:
クラスclass Super { char s = 's'; }
Super
のこの版は,Hyper
の下位クラスではない。次にHyper
及びTest
の既存のバイナリを,Super
の新しい版と共に実行すると,リンク時に,VerifyError
が投げられる。Super
は,Hyper
の下位クラスでないので,new
Super()
の結果は,型Hyper
の変数に代入できず,検証器はそれを受け付けない。
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
.検証段階がないと何が起こるかを検討することは例として価値がある。この場合,このプログラムを実行すると次の結果を出力する。
これは,個々のバイナリファイルが正しいJavaコンパイラによって生成されても,検証器なしでは,不整合なバイナリファイルをリンクすることによって型システムが崩れることを示す。s
検証器を欠いている,又は検証器を使うことに失敗している実装は,型の安全性を維持せず,したがって,妥当な実装ではない。
static
メンバ)と同じである,名前及びアクセス可能性(これらはフィールドに対する場合),又は名前,アクセス可能性,シグネチャ及び返却値型(これらはメソッドに対する場合)をもつインスタンスメンバ(及びstatic
メンバ)を追加することによって損なわれることはない。リンクされるクラスの集合がコンパイル時エラーに出会うような場合でも,(実行時には)エラーは発生しない。
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
と宣言されていないクラスメンバ又はコンストラクタの削除は,そのメンバ又はコンストラクタを既存のバイナリが使用する場合には,リンクエラーを引き起こすかもしれない。
private
may cause a linkage error if the member or constructor is used by a pre-existing binary.
このプログラムをコンパイルし実行すると,次の出力を得る。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(); } }
クラスhello from Super
Super
の新しい版が生成されたと仮定する。
Super
is produced:
class Super extends Hyper { }
Super
を再コンパイルし,この新しいバイナリをTest
及びHyper
の元のバイナリと共に実行すると次の出力を得る。
Super
and executing this new binary with the original binaries for Test
and Hyper
produces the output:
これは期待どおりの結果である。hello from Hyper
super
というキーワードは,現在のクラスの中で宣言されたメソッドをう(迂)回し,上位クラスの中で宣言されたメソッドにアクセスするために使用できる。次に式の例を示す。
super
keyword can be used to access a method declared in a superclass, bypassing any methods declared in the current class. The expression:
この式は,コンパイル時に,上位クラス S の中のメソッド M に解決される。メソッド M がインスタンスメソッドの場合,実行時に呼び出されるメソッド MR は,super.Identifier
super
を含む式を含むクラスの直接的上位クラスのメンバ M と同じシグネチャをもつメソッドとなる。次にプログラムの例を示す。
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(); } }
クラスhello from Hyper
Super
の次の新しい版を生成すると仮定する。
Super
is produced:
class Super extends Hyper { void hello() { System.out.println("hello from Super"); } }
Super
及びHyper
を再コンパイルし,Test
を再コンパイルしない場合,新しい(再コンパイルされた)バイナリをTest
の既存のバイナリと共に実行すると,次の出力を得る。
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
これは正しくない。)hello from Hyper
private
アクセスへ,protected
アクセスからデフォルトアクセス若しくはprivate
アクセスへ,又はpublic
アクセスからprotected
アクセス,デフォルトアクセス若しくはprivate
アクセスへ変更する場合とする。したがって,アクセス制限を許すメンバ又はコンストラクタの変更は,広く配布するクラスに対してしないほうがよい。
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.バイナリ形式は,メンバ又はコンストラクタをよりアクセス可能とする変更が,下位クラスが(既に)アクセス制限メソッドを定義している場合にはリンクエラーを生じないように定義されている。
そこで,例えば,パッケージpoints
がクラスPoint
を定義する場合を検討する。
points
defines the class Point
:
これを次のプログラムpackage points; public class Point { public int x, y; protected void print() { System.out.println("(" + x + "," + y + ")"); } }
Test
で使用する。
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
を実行すると,次の出力を得る。
Test
executes to produce the output:
クラスTest
Point
内のメソッドprint
をpublic
に変更し,クラスPoint
だけを再コンパイルし,Test
の既存のバイナリと共に実行する場合には,コンパイル時にpublic
なメソッドをprotected
なメソッドで上書きするのは不適当だが,リンクエラーは発生しない。(これは,print
をpublic
に変更しない限り,新しいクラスPoint
を使用してクラスTest
を再コンパイルすることはできない,という事実による。)
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
なメソッドに変更することを許していることで,バイナリをより壊れにくくしている。別の方法,すなわち,その変更がリンクエラーを引き起こす場合には,その方法は,付加的なバイナリ非互換性を生み出すことになる。
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.
フィールド f を型 T で限定して参照する場合を検討する。さらに,f は,実際に T の上位クラス S で宣言されたインスタンスフィールド(static
なフィールド)であって,f の型が X とする。f と同じ名前をもち,型が X の新しいフィールドを T の上位クラスである S 又は T それ自体の下位クラスに追加する場合,リンクエラーが発生する可能性がある。こうしたリンクエラーは,今示した場合に加えて,次の条件のいずれか一つが成立する場合にだけ発生する。
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:
static
フィールド(インスタンスフィールド)である場合。
static
(respectively instance) field.
これは次の出力を生成する。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); } }
hyper
Super
の定義を次のとおりに変更する。
Super
to be defined as:
class Super extends Hyper { String s = "super"; int h = 0; }
Hyper
及びSuper
を再コンパイルし,その結果の新しいバイナリを Test
の古いバイナリと一緒に実行すると,次の出力を得る。
Hyper
and Super
, and executing the resulting new binaries with the old binary of Test
produces the output:
hyper
Hyper
のフィールドh
は,main
の元々のバイナリによる出力になっている。これは,最初意外なことと思うかもしれないが,実行時に発生する非互換性の数を減らすのに有用である。(理想的には,その意外性を排除するために,再コンパイルが必要なすべてのソースファイルは,その一つでも変更されたときにはいつでも,再コンパイルするのがよい。しかし,特に,インターネットにおいていえるが,それらの膨大な再コンパイルは,実用的ではないか,又は不可能なことが多い。さらに,以前に示したとおり,それら再コンパイルは,ソースファイルの更なる変更を要求することもある。)
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.)
これをコンパイルし実行すると,次の出力を生成する。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); } }
クラスHyper
Super
の次の新しい版をコンパイルすると仮定する。
Super
is then compiled:
コンパイル結果のバイナリをclass Super extends Hyper { char h = 'h'; }
Hyper
及びTest
の既存のバイナリと一緒に使用する場合,依然として出力は次となる。
Hyper
and Test
, then the output is still:
このことは,これらバイナリに対する次のソースをコンパイルした場合にコンパイル時エラーを生ずるにも拘わらずいえる。Hyper
コンパイル時エラーの理由は,この場合には,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
に代入できないことによる。
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
なフィールドだけを,広く配布されるクラスから安全に削除してよい。
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.final
フィールド及び定数
final
Fields and Constantsfinal
でなかったフィールドをfinal
に変更する場合,そのフィールドに新しい値を代入しようとする既存のバイナリとの互換性が損なわれる。
final
is changed to be final
, then it can break compatibility with pre-existing binaries that attempt to assign new values to the field.
このプログラムをコンパイルし実行すると,次の出力を得る。class Super { static char s; } class Test extends Super { public static void main(String[] args) { s = 'a'; System.out.println(s); } }
クラスa
Super
の新しい版を作成したと仮定する。
Super
is produced:
class Super { final static char s = 'b'; }
Super
を再コンパイルしTest
を再コンパイルしない場合に,(Super
の)新しいバイナリとTest
の既存のバイナリとを一緒に実行すると,IllegalAccessError
が生ずる。
Super
is recompiled but not Test
, then running the new binary with the existing binary of Test
results in a IllegalAccessError
.
キーワードfinal
の削除又はフィールドの初期化値の変更は,既存のバイナリとの互換性を損なわない。
final
or changing the value to which a field is initialized does not break compatibility with existing binaries.
フィールドがコンパイル時定数の場合には,キーワードfinal
の削除又はその値の変更は,既存のバイナリとの互換性を損なわないが,これは,既存のバイナリが(フィールドアクセスを)実行しないことによる。ただし,既存のバイナリは,再コンパイルされない限りその定数に対する新しい値を見ることはない。
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.
これをコンパイルし実行すると,次の出力を得る。class Flags { final static boolean debug = true; } class Test { public static void main(String[] args) { if (Flags.debug) System.out.println("debug is true"); } }
クラスdebug is true
Flags
の新しい版を作成すると仮定する。
Flags
is produced:
class Flags { final static boolean debug = false; }
Flags
を再コンパイルするがTest
は再コンパイルしない場合,(Flags
の)新しいバイナリをTest
の既存のバイナリとを一緒に実行すると,次の出力を得る。
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
のコンパイル時に使用できたことによる。
debug
was a compile-time constant, and could have been used in compiling Test
without making a reference to the class Flags
.この結果は,14.20の最後に示したとおり,条件コンパイルをサポートするという決定の副作用である。
この振る舞いは,次の修正した例に示すとおり,Flags
をインタフェースに変更しても変わらない。
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
値の記号的リンクは行わない。)
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
な変数と,その値を得るための適切なアクセス用メソッドとを宣言するのを,よりよい選択とする。これを例で示す。
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; }
public static final int N = ...;
N
が読出し専用の必要がない場合には,次で問題はない。
一般的な規則として,真に変わらない定数値だけをインタフェースで宣言するのが望ましい。インタフェースのプリミティブ型のフィールドを変更してもよい場合には,その値は,慣用語法的に次のとおりに表現してよいことを注意しておく。ただし,これはしないほうがよい。public static int N = ...;
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(); }
注意するもう一つの点としては,定数値をもつstatic
でfinal
なフィールドは,(プリミティブ型又はString
型かどうかによらず,)決してそれ自体の型のデフォルト初期値をもつように見えてはならない(4.5.5)ことがある。これは,それらフィールドのすべては,クラスの初期化中に最初に初期化されるように見えることを意味する(8.3.2.1,9.3.1及び12.4.2)。
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).static
フィールド
static
Fieldsprivate
と宣言されていないフィールドが,static
と宣言されておらずstatic
と宣言されるように変更される場合,及びその反対の場合,そのフィールドが,他の種類のフィールドを期待する既存のバイナリによって使用されるときには,リンク時エラー,特に,IncompatibleClassChangeError
となる。これらの変更は,広く配布されるコードでは望ましくない。
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.transient
フィールド
transient
Fieldstransient
修飾子の追加又は削除は,既存のバイナリとの互換性を損なわない。
transient
modifier of a field does not break compatibility with pre-existing binaries.
型 T の限定をもつメソッド m への参照を検討する。さらに,m が,実際に T の上位クラス S で宣言されたインスタンスメソッド(static
なメソッド)であると仮定する。m と同じシグネチャ及び返却値型をもつ型 X の新しいメソッドが,T の上位クラスである S 又は T それ自体の下位クラスに追加される場合,リンクエラーが発生することがある。そうしたリンクエラーは,今示した場合に加えて,次の条件のいずれか一つが成立する場合にだけ発生する。
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:
static
メソッド(インスタンスメソッド)である場合。
static
(respectively instance) method.NoSuchMethodError
が投げられる可能性がある。これらエラーは,合致するシグネチャ又は返却値型をもつメソッドが上位クラスで宣言されていない場合にだけ発生する。
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コンパイラは,自動的に仮引数をもたないコンストラクタを供給する。それらのクラスのソースコードに,一つ以上のコンストラクタ宣言を追加すると,このデフォルトのコンストラクタが自動的に生成されることを防ぐことができる。これは,実効的には(デフォルト)コンストラクタを削除することを意味する。ただし,新しく作成したコンストラクタの一つが仮引数をもつ場合には,デフォルトコンストラクタを置き換えることになる。自動的に供給される仮引数をもたないコンストラクタには,その宣言のクラスと同じアクセス修飾子を与える。したがって,既存のバイナリとの互換性を維持するほうがよい場合には,あらゆる置換えは,同じ又はより多くのアクセスをもつことが望ましい。
void
への置換え,又はvoid
の結果の型への置換えは,古いメソッドの削除,及び新しい結果の型又は新しいvoid
の結果をもつ新しいメソッドの追加を組み合わせた影響をもつ(13.4.11参照)。
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).abstract
メソッド
abstract
Methodsabstract
宣言をしているメソッドをabstract
宣言しないと変更することは,既存のバイナリとの互換性を損なわない。
abstract
to no longer be declared abstract
does not break compatibility with pre-existing binaries.
abstract
宣言をしていないメソッドをabstract
宣言すると変更することは,以前にそのメソッドを呼び出していた既存のバイナリとの互換性を損ない,AbstractMethodError
を引き起こす。
abstract
to be declared abstract
will break compatibility with pre-existing binaries that previously invoked the method, causing an AbstractMethodError
.
このプログラムをコンパイルし実行すると,次の出力を得る。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(); } }
クラスWay Out
Super
の新しい版を作成したと仮定する。
Super
is produced:
abstract class Super { abstract void out(); }
Super
は再コンパイルするがTest
は再コンパイルしない場合,新しいバイナリをTest
の既存のバイナリと共に実行すると,AbstractMethodError
を生ずる。これは,クラスTest
は,メソッドout
の実装をもたず,そのため抽象的となる(又は抽象的となるのが望ましい)ことによる。
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. final
メソッド
final
Methodsfinal
でないインスタンスメソッドをfinal
に変更することは,メソッドの上書きが可能なことに依存する既存のバイナリとの互換性を損なうことがある。
final
to be final
may break compatibility with existing binaries that depend on the ability to override the method.
このプログラムをコンパイルし実行すると,次の出力を得る。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(); } }
クラスout
Super
の新しい版を作成したと仮定する。
Super
is produced:
class Super { final void out() { System.out.println("!"); } }
Super
は再コンパイルするがTest
は再コンパイルしない場合,新しいバイナリをTest
の既存のバイナリとともに実行すると,VerifyError
を生ずる。これは,クラスTest
は,インスタンスメソッドout
を不適切に上書きしようと試みたことによる。
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
に変更することは,既存のバイナリとの互換性を損なわない。これは,メソッドが上書きされることは可能ではなかったことによる。
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
修飾子を削除することは,既存のバイナリとの互換性を損なわない。
final
modifier from a method does not break compatibility with pre-existing binaries.native
メソッド
native
Methodsnative
修飾子を追加又は削除することは,既存のバイナリとの互換性を損なわない。
native
modifier of a method does not break compatibility with pre-existing binaries.
再コンパイルしていない既存のnative
メソッドに関する型への変更の影響は,この規定の適用範囲外とし,実装の記述で提供されることが望ましい。実装処理系は,その影響を制限する方法で,native
メソッドを実装することが望ましいが,必須ではない。
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.static
メソッド
static
Methodsprivate
宣言していないメソッドがstatic
宣言されていた(すなわち,クラスメソッドであった)場合であって,それを,static
宣言しない(すなわち,インスタンスメソッドとする)に変更する場合,又はその逆の場合,既存のバイナリとの互換性は損なわれる可能性があり,これらのメソッドを既存のバイナリとともに使用すると,リンク時エラー,IncompatibleClassChangeError
となる。広く配布されているコードに対しては,それらの変更はしないほうがよい。
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.synchronized
メソッド
synchronized
Methodssynchronized
修飾子を追加又は削除することは,既存のバイナリとの互換性を損なわない。
synchronized
modifier of a method does not break compatibility with existing binaries.throws
節
throws
節の変更は,既存のバイナリとの互換性を損なわない。この節は,コンパイル時にだけ検査される。
throws
clause of methods or constructors do not break compatibility with existing binaries; these clauses are checked only at compile time.コンパイラは,コンパイル時にメソッドをインライン展開できないことに注意すること。
メソッドのキーワードfinal
は,メソッドが安全にインライン展開できるという意味ではない。それは,単にそのメソッドが上書きできないことだけを意味する。そのメソッドの新しい版をリンク時に提供することは依然として可能とする。さらに,元のプログラムの構造は,自己反映性の目的のために保存されなければならない。
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.一般に,実装は,遅延束縛の(実行時の)コード生成及び最適化を使用するほうがよい。
新しくオーバロードされたメソッド又はコンストラクタを追加することは,そのクラス又はインタフェースを次にコンパイルする時に,コンパイル時エラーとなる可能性がある。これは,最も特殊なメソッド又はコンストラクタが存在しないことによる(15.12.2.2)。その一方で,プログラムが実行された時には,それらのエラーは発生しない。これは,オーバロードの解決は,実行時には行われないことによる。
このプログラムをコンパイルし実行すると,次の出力を得る。class Super { static void out(float f) { System.out.println("float"); } } class Test { public static void main(String[] args) { Super.out(2); } }
クラスfloat
Super
の新しい版を作成すると仮定する。
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
の既存のバイナリと一緒に実行すると,依然として,次の出力を得る。
Super
is recompiled but not Test
, then running the new binary with the existing binary of Test
still produces the output:
しかし,この新しいfloat
Super
を使用してTest
を再コンパイルする場合には,次の出力を得る。
Test
is then recompiled, using this new Super
, the output is then:
これは,先のプログラムが,素朴に期待していた結果である。int
public
インタフェース
public
Interfacespublic
宣言をしていないインタフェースをpublic
宣言に変更することは,既存のバイナリとの互換性を損なわない。
public
to be declared public
does not break compatibility with pre-existing binaries.
public
宣言をしているインタフェースをpublic
宣言をしないと変更した場合,そのインタフェース型を必要とするがもはやアクセスをもたない既存のバイナリをリンクしたとき,IllegalAccessError
が投げられる。したがって,広く配布されるインタフェースに対しては,それらの変更はしないほうがよい。
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.VerifyError
を生ずることがある。
VerifyError
.IncompatibleClassChangeError
が生ずる。元の参照が代入であった場合には,IllegalAccessError
が生ずる。
IncompatibleClassChangeError
will result. If the original reference was an assignment, an IllegalAccessError
will result.インタフェースからのメンバの削除は,既存のバイナリにおいてリンクエラーを引き起こすことがある。
このプログラムをコンパイルし実行すると,次の出力を得る。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"); } }
インタフェースhello
I
の新しい版を作成すると仮定する。
I
is compiled:
interface I { }
I
を再コンパイルするがTest
を再コンパイルしない場合,新しいバイナリをTest
の既存のバイナリと一緒に実行すると,NoSuchMethodError
を生ずる。(初期の実装では,このプログラムは動作することがあった。これは,メソッドhello
がもはやインタフェースI
に存在しないという事実が,正しく検知されなかったことによる。)
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.)static
final
フィールドに対するものと同じとする。
static
final
fields in classes, as described in §13.4.7 and §13.4.8.abstract
メソッド宣言
abstract
メソッドに対するものと同じとする。
abstract
methods in classes, as described in 13.4.12, 13.4.13, 13.4.19, and 13.4.21.
目次 | 前 | 次 | 索引 | Java言語規定 第2版 |