Java 2 プラットフォーム
旧バージョンとの互換性
|
SDK 目次
 |
目次
このドキュメントには、以下の項目に関する情報が含まれます。
Java プラットフォームのバージョン 1.1 と 1.2 の間の非互換性については、Java 2 プラットフォーム, v1.2 の互換性についてのドキュメントを参照してください。
Java プラットフォームのバージョン 1.0 と 1.1 の間の非互換性については、JDK 1.1 の互換性についてのドキュメントを参照してください。
最初に Java 言語仕様が発表されて以来 Java プログラミング言語の仕様に対して行われた変更の概要は、「Clarifications and Amendments」を参照してください。
後述の「バージョン 1.3 における非互換性」で説明されている項目を除き、Java 2 SDK, v1.3 は、Java 2 SDK, v1.2 に対してバイナリレベルの上位互換性があります。つまり、互換性のないことが示されている機能を除き、バージョン 1.2 のコンパイラで作成されたクラスファイルは、Java 2 SDK, v1.3 で正常に動作します。
Javac コンパイラのコマンド行オプション「-target 1.2」を使用しない場合、バイナリレベルの下位互換性は一般的にサポートされますが、保証はされません。Java 2 SDK のコンパイラで生成されているクラスファイルでも、Java プラットフォームのバージョン 1.0 または 1.1 で定義されている API だけを使っている場合は、通常、バージョン 1.0 および 1.1 の Java Virtual Machine 上で動作します。ただし、この「下位」互換性は全機能について検査されているわけではなく、保証はされません。また、新しく追加された Java 2 プラットフォーム API をクラスファイルで使っている場合は、それより前のプラットフォームでは動作しません。
一般的な原則は次のとおりです。
- ファミリ (1.2.x) 内の保守リリース (1.2.1、1.2.2 など) の間では、バイナリレベルの上位互換性および下位互換性が保証される
- ファミリ (1.x) 内の機能リリース (1.2、1.3 など) の間では、バイナリレベルの上位互換性は保証されるが、下位互換性は保証されない場合がある
初期のオブファスケータ (obfuscator) の中には、Virtual Machine の仕様で規定されているクラスファイルの形式に違反するクラスファイルを生成するものがありました。そのような不適切な形式のクラスファイルは、旧バージョンの Java Virtual Machine では動作する場合もありますが、Java 2 SDK の Virtual Machine では動作しません。この問題を回避するには、適切な形式のクラスファイルを生成する新しいオブファスケータで、クラスファイルを生成し直してください。
後述の「バージョン 1.3 における非互換性」で説明されている項目を除き、Java 2 SDK のバージョン 1.2 および 1.3 は、JDK ソフトウェアのバージョン 1.0 および 1.1 に対してソースレベルの上位互換性があります。つまり、互換性のないことが示されている機能を除き、バージョン 1.0 および 1.1 で定義されている言語機能および API を使って記述されたソースファイルは、Java 2 SDK (バージョン 1.2 および 1.3) でコンパイルして実行できます。
ソースレベルの下位互換性はサポートされていません。新しい言語機能または Java 2 プラットフォーム API を使っているソースファイルは、旧バージョンの Java プラットフォームでは使用できません。
一般的な原則は次のとおりです。
- 保守リリースでは、新しい言語機能または API は導入されないので、ソースレベルでの互換性が両方向に対して保証される
- 機能リリースおよびメジャーリリースでは、ソースレベルの上位互換性は保証されるが、下位互換性は保証されない
推奨されない API は、下位互換性のためだけにサポートされているメソッドやクラスです。推奨されない API を使った場合、コマンド行オプションで -nowarn を指定しないと、コンパイラが警告メッセージを出力します。現時点では、推奨されないメソッドやクラスをシステムから完全に削除する予定はありませんが、推奨されないメソッドとクラスを使わないようにプログラムを修正することをお勧めします。
sun.* パッケージに含まれる API の中には、変更されているものがあります。このパッケージの API は、開発者用のものではありません。開発者が sun.* パッケージからインポートする場合は、各自の責任において行なってください。詳細は、開発者が sun.* パッケージを呼び出すプログラムを記述すべきでない理由を参照してください。
Java 2 Platform, Standard Edition, v1.3 における非互換性
J2SE 1.3 には、J2SE 1.2 および 1.2.2 との高い互換性があります。このため、既存のプログラムの多くは J2SE 1.3 でもそのまま実行できます。ただし、非常にまれな例ですが、互換性が提供されない場合もあります。ここでは、こうした非互換性について説明します。
- 新規クラス java.util.Timer が、Java 2 プラットフォームのバージョン 1.3 に追加されました。それにより、Timer という名前のクラスが 2 つになりました。
- java.util.Timer
- javax.swing.Timer
java.util.Timer の追加により、以下の 2 つの import 文を含む既存コードで、
import java.util.*;
import javax.swing.*;
javax.swing.Timer に対して次のような非修飾名で参照していると、ソースレベルで非互換性が発生します。
Timer t;
クラス Timer へのあいまいな参照は、次の 3 番目の import 文を追加することにより javax.swing.Timer を参照するようになります。
import javax.swing.Timer;
この 3 番目の import 文を適切に置くと、ソースコードは以前のバージョンのプラットフォームと同様にコンパイルされて動作します。
- メソッド java.lang.Double.hashcode の実装は、Java 2 SDK, v1.3 では API 仕様に準拠するよう変更されました。また、仕様内の誤記も訂正されました。メソッド hashcode の仕様には、以前は以下の文がありました。
"That is, the hashcode is the value of the expression:
(int)(v^(v>>>32))
where v is defined by:
long v = Double.doubleToLongBits(this.longValue());"
この最後の文は、1.3 の API 仕様で次のように修正されました。
long v = Double.doubleToLongBits(this.doubleValue());
SDK のこのメソッドの実装は、仕様に準拠して次を返すように変更されました。
(int)(bits ^ (bits >>> 32))
bits は doubleToLongBits(value) です。SDK の以前のバージョンでは、メソッド hashcode は次を返していました。
(int)(bits ^ (bits >> 32))
hashcode は切り捨てられた整数値を返すので、実装に加えられたこの変更によって既存のアプリケーションの動作が影響を受けることはありません。
- Java 2 プラットフォームのバージョン 1.3 で、新しい Permission クラス java.sql.SQLPermission が追加されました。
セキュリティマネージャは、アプレットで実行中のコードが以下のどれかのメソッドを呼び出すと、SQLPermission をチェックします。
java.sql.DriverManager.setLogWriter
java.sql.DriverManager.setLogStream (推奨されない)
javax.sql.DataSource.setLogWriter
javax.sql.ConnectionPoolDataSource.setLogWriter
javax.sql.XADaaSource.setLogWriter
|
J2SE 1.3 では、適切な SQLPermission を持たないアプレットがログライターを設定しようとすると、例外がスローされます。
- バージョン 1.3 の Java Sound API (クラス com.sun.media.sound.SimpleInputDevice) の内部実装は、javax.sound.sampled.AudioPermission をチェックします。バージョン 1.3 のアプレットには、オーディオシステムリソースにアクセスするための適切な AudioPermission が必要です。旧バージョンのプラットフォームでは、これは必須条件ではありませんでした。
- JInternalFrame のデフォルトは可視でなくなりました。Java 2 プラットフォームのバージョン 1.3 以降は、JInternalFrame を画面上に表示するには、各 JInternalFrame の可視状態を true に設定する必要があります。以前のバージョンのプラットフォームでは、JInternalFrame の可視状態はデフォルトで true に設定されていました。
変更の理由は以下のとおりです。Swing のデフォルト可視状態の規則では、JFrame や JDialog などのトップレベルのコンポーネントのみデフォルト可視状態が false で、それ以外のコンポーネントは true です。これは、JFrame が構築されたあとは、JFrame で 1 回 setVisible(true) が呼び出されると JFrame とその内容のすべてが表示されるようになるからです。
JInternalFrame は実際にはトップレベルのコンポーネントではありませんが、多くの点で JFrame と同じように動作する必要があります。特に、JFrame での Window イベントに対応して JInternalFrame イベントを生成する必要があります。このようなイベントの 1 つである INTERNAL_FRAME_OPENED は、初期可視状態が false から true に変わると、それに応答して生成されます。1.3 より前のバージョンでは、このように可視状態が変わることによってイベントが生成されることはありませんでした。
このバグを修正し、JInternalFrame に重量同系オブジェクトの JFrame との互換性をもたせるために、Java 2 プラットフォームのバージョン 1.3 から JInternalFrame のデフォルト可視状態を false に変更しました。その結果、フレームをその親に追加したあとで setVisible(true) を呼び出すだけで、内部フレームが表示されます。
JInternalFrames が 1.2.x または 1.3 で確実に可視状態になるようにするには、setVisible を呼び出す必要があります。デフォルトでフレームが可視である場合でも、1.2 でこの呼び出しを行なっても問題は生じません。
- バージョン 1.3 では、TableColumn.getHeaderRenderer メソッドはデフォルトで null を返します。そのため、デフォルトのヘッダレンダリングの取得には使用できません。代わりに、新しい JTableHeader.getDefaultRenderer メソッドを使用することができます。
1.2.x および 1.3 で動作する同じコードが必要な場合には、上記のメソッドを使用することができます。デフォルトのレンダリングを取得するために getHeaderRenderer メソッドを使用する場合には、代わりに新しいレンダリングを作成することができます。例を次に示します。これは、1.2.x および 1.3 で動作します。
/*Original code*/
DefaultTableCellRenderer hr =
(DefaultTableCellRenderer)column.getHeaderRenderer();
hr.setHorizontalAlignment(SwingConstants.LEFT);
/*Fixed code*/
DefaultTableCellRenderer hr = new DefaultTableCellRenderer();
hr.setHorizontalAlignment(SwingConstants.LEFT);
column.setHeaderRenderer(hr);
|
- バージョン 1.3 の JTable のデフォルトテキストエディタは、データ型に関してより洗練されているので、このエディタは、常に文字列を指定しなくても、適切な型の setValueAt オブジェクトを提供します。たとえば、Integer のセルに対して setValueAt が呼び出されると、値は String ではなく Interger として指定されます。テーブルモデルを実装した場合、新しいデータ型を考慮するようにその setValueAt メソッドを変更しなければなりません。セルのデータ型として使用されるクラスを実装した場合は、必ず、クラスに単一の String 引数をとるコンストラクタを持つようにしてください。
- リリース 1.2.x では、十分に信頼されたコードでは、最初に Field.setAccessible(true) を呼び出してから Field.set() を呼び出すことによって final フィールドを変更することができました。Field.set() の仕様ではこのような場合に IllegalAccessException をスローすると記述されているので、これは明らかにバグでした。このバグは、バージョン 1.3 で修正されています。旧バージョンでは、このバグのため、プログラムコードが不適切な動作を信頼してしまうことがありました。
- Java 2 SDK および Java 2 Runtime Environment のバージョン 1.2、1.2.1、および 1.2.2 のバグ (バグ ID 4250960) により、十分に信頼されるコードが、最初に java.lang.reflect.Field.setAccessible(true) を呼び出してから Field.set() を呼び出すことによって final フィールドの値を変更することができていました。この方法で final フィールドを変更できるということは、Field.set() の仕様に違反しているため、バグと考えられます。Field.set() の仕様では、final フィールドに変更を加えようとすると、IllegalArgumentException がスローされると記述されています。
このバグはバージョン 1.3 で修正されています。旧バージョンでは、このバグのため、プログラムコードが不適切な動作を信頼してしまうことがありました。
現在でも、非 static の final フィールドを、JNI Set<type>Field ルーチンを介して設定することはできます。
- java.security.BasicPermission クラスのコンストラクタ BasicPermission(String name) および BasicPermission(String name, String actions) の仕様と動作は、Java 2 プラットフォームのバージョン 1.3 で変更されました。name パラメータが null の場合、コンストラクタは NullPointerException をスローするようになりました。name パラメータが空白文字の場合、コンストラクタは
IllegalArgumentException をスローするようになりました。この動作上の変更は、BasicPermission のサブクラスによって継承されます。
この変更により、その実装が PropertyPermission (BasicPermission のサブクラス) のインスタンスを生成する、java.lang.System.getProperty() および java.lang.System.setProperty() の動作にも影響を与えます。変更後は、getProperty または setProperty を空のプロパティ名 (つまり、getProperty("") または setProperty("", value)) で呼び出すと、IllegalArgumentException がスローされます。このプラットフォームの以前のバージョンでは、例外は発生せずに呼び出しが復帰していました。
- java.net.URL の動作が、URL インスタンスが String から生成される場合のために、少し変わりました。以前のバージョンの Java プラットフォームでは、String なしで URL が構築された場合、スラッシュ (/) が URL の最後に追加されていました。たとえば、次のコードについて見てみます。
URL url = new URL("http://www.xxx.yyy");
System.out.println(url.toString());
以前のリリースでは、このコードによって次の URL が出力されました。
http://www.xxx.yyy/
1.3 では最後尾のスラッシュは自動的には追加されないため、上記のコードによる出力は次のようになります。
http://www.xxx.yyy
以前の動作は技術的にはバグであり、この変更によって以前のリリースとの間で互換性の問題が生ずることは考えられません。
- バージョン 1.3 の javac コンパイラの新しい実装が提供されることにより、互換性に関して以下のような差異が生じます。
- 囲みクラスの継承メンバが参照可能になった
Java 言語仕様 (Java Language Specificaton, Second Edition) では、クラスの継承メンバは、入れ子のクラスも含めたクラス内で参照可能であるとされています。Java 2 SDK のバージョン 1.1 および 1.2 では、メンバが実際に囲みクラス内で「宣言されている」場合にのみ、入れ子のクラス内での参照を可能とみなしていました。Java 2 SDK, v1.3 の新しいコンパイラは、仕様に準拠するように変更されました。
- ローカル変数とパラメータの隠蔽
Java 言語仕様では、ローカル変数や catch 節が同じ名前のメソッドパラメータ、ローカル変数、または catch 節パラメータのスコープ内で宣言されている場合に、エラーを報告することが要求されています。しかし、以前のコンパイラでは、多少不規則に実施されていました。仕様では、この規則が単一メソッドに属する変数およびパラメータにのみ適用されることが、明確にされました。メソッドがもうひとつのメソッド内で入れ子になっている場合、たとえば、ローカルクラスのメンバのような場合、内部メソッドのローカル変数およびパラメータは、外部メソッドのローカル変数およびパラメータを覆い隠します。
- 型とサブパッケージの間の名前の重複
Java 言語仕様 (Java Language Specification, Second Edition) のセクション 7.1 によると、パッケージに同じ名前のクラスやインタフェースの型およびサブパッケージを含むことは不正です。バージョン 1.3 より前には、この規則はほとんど遵守されていませんでした。新しいコンパイラは、この規則を一貫して遵守するようになっています。パッケージ、クラス、またはインタフェースは、クラスパスやソースパス上で参照が可能な対応するディレクトリ、ソースファイル、またはクラスファイルがあれば、その内容にかかわらず、存在するものとみなされます。
- 定数式での修飾名
Java 言語仕様 (Java Language Specification, Second Edition) のセクション 15.28 によると、定数式である修飾名は、「型名.識別子」の形式でなければなりません。したがって、フィールド foo 自体が定数であるかどうかにかかわらず、式 x.foo (x は変数かまたはその他の式) は、定数式が要求されるコンテキスト内で使用されることはありません。バージョン 1.3 より前は、javac は警告を発することなくこのような構文を受け入れ、x はその型によって置き換えられるものとして処理し、式の実行によって生じる可能性のある副作用を無視しました。
- インタフェースのメンバクラスがクラスの実装により継承されるようになった
バージョン 1.3 より前は、インタフェースのメンバクラスは、クラスの実装によっては継承されませんでした。これは、実装で見落とされていた点でした。仕様では、フィールドに対して同様に適用される原則に従って、メンバクラスが継承されることを要求しています。
- バージョン 1.3 では、パフォーマンスの改善策として、ObjectInputStream が着信データをバッファに入れるように最適化されています。この変更に伴い、ObjectInputStream は、元になるストリームの複数バイトの read(byte[], int, int) メソッドをこれまでよりも頻繁に呼び出すようになりました。このため、このメソッドを正しく実装していないストリームクラスによって、直列化に失敗することも多くなっています。予期しない動作を回避するには、元になるストリームが単一バイトの read() メソッドと複数バイトの read(byte[], int, int) メソッドを両方とも正しく実装していなければなりません。
- Java 2 Runtime Environment のバージョン 1.2 には、Internet-Intranet Input Method Protocol (IIIMP) 用のクライアント側アダプタが含まれていました。IIIMP とは、ネットワークを介したサーバベースのインプットメソッドの利用を可能にする、Sun Microsystems のテクノロジです。このアダプタが含まれていると、ユーザがアダプタを Java Runtime Environment に個別のソフトウェアコンポーネントとしてインストールするための public インタフェースがない場合に、このプロトコルの評価を行うことができます。Java 2 プラットフォームのバージョン 1.3 では、public インプットメソッドエンジン SPI を提供することにより、アダプタを他の入力システムと同様に開発し、個別の製品として配布し、Java 2 プラットフォームの実装のいずれかにインストールすることを可能にします。SPI を使用する IIIMP アダプタは現在 Sun Microsystems で開発中です。最新の情報については、Solaris Developer Connection にアクセスして、「IIIM」で検索してください。
テキストエントリにサーバベースのインプットメソッドの使用を許可するような環境では、ホストインプットメソッドや Sun の IIIMP アダプタ (クライアント側のアダプタ) を使用するソリューションを選択する必要があります。
- 以前のバージョンの JVM および JDK のネイティブライブラリは、ARM ベースの ANSI/ISO 以前の C++ ABI で書かれたネイティブ C++ コード (Workshop SC4.2 や初期の C++ コンパイラで使用したコードなど) との互換性を保つために、"-compat=4" モードでコンパイルされていました。J2SE 1.3.0 から、JVM およびネイティブライブラリは、ANSI/ISO C++ に対応する「標準」モードでコンパイルされています。この変更により、既存のネイティブ C++ ソースコードで、ANSI/ISO 以前の古い C++ を使用するものや、古いバージョンの JVM で動作するものは、(特に C++ の例外を使用する場合は) J2SE 1.3.0 と互換性がなくなります。該当するネイティブ C++ コードは、J2SE 1.3.0 以降で動作するように「標準」ANSI C++ モードに移行する必要があります。
Solaris オペレーティング環境用 Java 仮想マシンのバージョン 1.3.0 は、Solaris 2.6 上で Sun WorkShop 5.0 C++ コンパイラの「標準」(ANSI/ISO C++) モードで「従来の」iostream を使用して構築されました。
- J2SE 1.3.0 より前は、Microsoft Windows 版の javac コンパイラでは、パッケージパスのディレクトリ名の大文字と小文字は区別されていませんでした。J2SE 1.3.0 以降は、ディレクトリ名の大文字と小文字が区別されます。J2SE 1.3.0 の javac コンパイラでは、パッケージパスのディレクトリ名とパッケージ名がすべての文字について大文字と小文字の種類も一致していないと、「シンボルを解釈処理できません」というエラーが出力されます。
|