目次 | |

附属書A(参考) Java 1.1に対する変更

序文 

この附属書(参考)は,Addison-Wesley社から発行されているJava Programming LanguageのJava 1.1対応の付録を,この規定本文に即して記述し直したものであって,規定の一部ではない。

この規定本文の最初の制定後に、Javaの新しい版が制定された。これをJava 1.1 基盤(以降では簡単にJava 1.1)と呼ぶ。Java 1.1は,いくつかの言語特徴,いくつかのパッケージ及び既存のパッケージへの多くのクラスを追加する。Java 1.1 の目的は,より良い国際化対応,この規定本文の元となった Java 仕様の抽象ウィンドウツールキットパッケージ(java.awt 又は単に省略形で "AWT")の修正,存在していなかった又は不足していた機能の完結及びいくつかの有用なパッケージの追加とする。ただし,この規定本文はAWT を含んでいない。そこで,この附属書(参考)でも AWT については含めない。

この附属書(参考)では,これ以外の変更もまとめる。拡張的な変更,特に,新しいクラス及びパッケージを扱う変更については,この附属書(参考)を補完するために,(Sun 社の)Java 1.1 処理系と共に配布される参照文書を使用することが望ましい。

A.1 クラス

A.1.1 内部クラス

クラス及びインタフェースを他のクラス内に入れ子可能とする。内部クラス(inner classes) と呼ぶこのようなクラスは,それが入れ子されているクラスの作業を支援するためにだけ存在することが望ましい。例を次に示す。

    abstract class SortDouble {
	static final class SortMetrics implements Cloneable {
	    // ... the rest of SortMetrics
	}
	// ... the rest of SortDouble
    }

クラス SortMetrics の唯一の目的は,クラス SortDouble の他のメソッドから複数の値を返すこととする。これは,内部クラスとすることが望ましい候補となる。内部クラスの名前は,内部クラスを含む外包クラス(enclosing class)によって限定する。この例では,SortMetrics の適切な名前は, SortDouble.SortMetrics とする。この名前を使った宣言の例を次に示す。

    SortDouble.SortMetrics metrics = bsort.sort(testData);
内部クラス及び内部インタフェースは,クラスの他のメンバと同じアクセス修飾子を使用可能とする。内部データ構造でだけ使用するクラスは private 宣言するかもしれない。サブクラスでだけ使用することを意図しているものは protected 宣言するだろう。内部クラスは, public 宣言する又はアクセス可能パッケージとすることも可能とする。

上記の例は,SortMetricsstatic 宣言している。静的でない内部クラスは,内部クラスオブジェクトを作成した,内部クラスを含む外包オブジェクト(enclosing object)への暗黙の参照をもつ。多くの内部クラスは,特定のオブジェクトと緊密に連携し,それらのフィールドにアクセスするために必要なので,この参照は有用とする。

次の例を考える。

    public class WhichChars {
	private BitSet used = new BitSet(); 
	private class Enumerate implements Enumeration {
	    private int pos = 0;
	    private int setSize = used.size();

	    public boolean hasMoreElements() {
		while (pos < setSize && !used.get(pos))
		    pos++;
		return (pos < setSize);
	    }

	    public Object nextElement()
		throws NoSuchElementException
	    {
		if (hasMoreElements())
		    return new Character((char)pos++);
		else
		    throw new NoSuchElementException();
	    }
	}

	public Enumeration characters() {  
	    return new Enumerate();
	}
    }

クラス Enumerate は, WhichChars 内に入れ子になっている。このクラスは private 宣言されており,パッケージ内の他のクラスは,この型に直接にはアクセスできない。つまり,このクラスは,真にクラス WhichChars の実装の詳細となっている。

Enumerate のコードは,外包オブジェクトのフィールド used に直接アクセスする。識別子を解決するとき,外包オブジェクト(これはまた外包インスタンス(enclosing instance)とも呼ぶ)が,そのクラス自体の this の後に,フィールド及びメソッドに対する検索の対象となる。 Enumerate は, used という名前のフィールドをもたないので,内部クラス内の識別子 used は,その名前の外包オブジェクトのフィールドを参照する。内部オブジェクトに対する外包オブジェクトは,その内部クラスオブジェクトを作成したメソッドの this 参照とする。上記の例では,オブジェクト Enumerate を特定のオブジェクト WhichChar 内に作成したとき,オブジェクト Enumerate の外包オブジェクトを,それを作成したメソッド WhichCharthis 参照に設定する。 このことは,(静的メソッド又は静的ブロック内での,並びに静的フィールドに対する初期化子としての)静的文脈内での非静的内部クラスのインスタンスを作成できないことを意味している。

クラス名を使って外包オブジェクトへの参照を得ることは可能とする。例えば,オブジェクト Enumerator 内のコードは, WhichChar.this を使って外包オブジェクトへの参照を得ることができる。

A.1.2 final に対する新しい用法

メソッド仮引数及び局所変数を final 宣言できる。メソッド内の仮引数又は変数の値を変化させたくなければ,final と宣言し,コンパイラにこのことを強制することを可能とする。コンパイラは,値が決して変化しないことを知ることで,final 仮引数又は変数の使用を最適化することも可能とする。

仮引数の final という性質は,メソッドシグネチャの一部ではなく,単に実装の詳細とする。サブクラスは,メソッドを上書きして,望むとおりに final 修飾子を追加又は削除することを可能とする。メソッドを使用する既存のコンパイル済みコードにいかなる問題も引き起こさなければ,メソッド仮引数内の final 修飾子を追加又は削除できる。final 宣言は,文書化注釈から生成される文書内には現れない。

final フィールド又は変数を使用する前に初期化し,ただ一度だけ値を代入する限りにおいては,そのフィールド又は変数の初期化を変えることも可能とする。コンパイラは,検証器がコードを実行する前に検査するように,適正な代入に関して検査をする。変数初期化子内で符号化することが困難又は不可能なループ又は他のコードであって,捕捉及び処理しなければならない例外を投げるようなコードによってだけ適正な値が計算可能なとき,初期化の変更は有用とする。

A.1.3 オブジェクト初期化子

スーパクラスのコンストラクタを実行する後で,クラスそれ自体のコンストラクタ本体を実行する前に実行する任意のコードブロックをもつことができる。このようなブロックは,キーワード static をつけないということ以外は static ブロックと類似する。

A.2 クラスの拡張

A.2.1 無指定クラス

単純なサブクラス又はインタフェースの実装を書くときに,各自明なクラスにためのクラスの集まりを作ることは,あまり良いやり方とはいえない。無指定クラス(anonymous class) は,名前をもたない内部クラスの便利な短縮形であって,new の右側にだけ指定する実装とする。オブジェクトのフィールドに格納されたイベントの履歴を保持する単純なオブジェクト Observer を作成したいとする。次の例は,このことを直接及び単純に行う。

    private Vector history = new Vector();

    public void watch(Observable o) {
	o.addObserver(new Observer() {
	    public void update(Observable o, Object arg) {
		history.addElement(arg);
	    }
	});
    }

addObserver は,暗黙的に Object を拡張してインタフェース Observer を実装する無指定クラスの埋め込まれた new をもつ。この無指定クラスは,外包オブジェクトのベクトル history に要素を追加することによって,update を実装する。コンパイラは,指定された update を上書きする名前無しの(したがって無指定の)クラスを作成する。無指定クラス宣言の終わりは, new によって開始する割当て式の終わりとする。この例では,単に,括弧を閉じることで addObserver の呼出しを終了する。

無指定クラスは,インタフェースを実装する代わりに,クラスを拡張できる。この場合には,拡張したクラスは元のクラスの名前無しの部分型(subtype) とする。このような new は,任意のスーパクラスコンストラクタを呼び出すことが可能とする。無指定クラスは,それ自体のコンストラクタをもつことができない。

無指定クラスは,それ自体が小さな動作をもつ AWT ボタンの型の作成又は単純な Runnable オブジェクトの作成のような状況において役に立つ,すばやく,簡潔なサブクラス化ツールとする。残念なことに,多くの簡潔性特徴に共通する問題点をもつ。つまり,読むのが大変なコードを書き下す単調な作業が必要となる。一つ又は多くとも二つの,全体でも4行以下のメソッドを上書きする小さなクラスに対してだけ,無指定クラスを使用することが望ましい。そうでないときには,コードを読む者が,どのクラスのメソッドのコードの断片を読んでいるのか,及び外部の文脈は何なのかを覚えておこうとしても,混乱を生じてしまう。このツールは,予備的なものとして使うことが望ましい。効果的に使用するときは強力だが、そうでないときには,問題を生じる。

A.2.2 新しいハッシュ方式

Object.hashCode のデフォルトの実装は,違ったオブジェクトに対して違ったキーを返す。多くのクラスは,等価の違った概念を提供するために hashCode 及び equals の両方を上書きする。しかし,ときには等価の元の概念,普通は広い意味において使用されているオブジェクトに対しても,すべてのオブジェクトを違うとする概念,を必要とすることがある。== を二つのオブジェクトが同じかどうかを試験するために使用できる。しかし,オブジェクトをハッシュするためには System.identityHashCode を使用する必要がある。これは,すべてのオブジェクトを違うものと考える hashCodeのデフォルト実装を保持しているからである。

A.3 トークン,演算子及び式

文書化用注釈は,(@author 及び @see のような)@ タグを含む。新しいタグ @deprecated は特別の意味をもつ。つまり,今後は使用しないことが望ましいクラス,インタフェース,フィールド又はメソッドを印付けする。使用しないことが望ましい実体を使用している既存のコードは,そのままコンパイル及び実行するが,コンパイラは,警告を生成し,その実体を避けるようにコードを修正することを提案する。この勧告に従うことが望ましい。

型又は型のメンバに対してこの効果をもたせるには,タグ @deprecated は,文書化用注釈の最初に存在しなければならない(ただし,空白類及び任意の * 文字は無視する)。この場所は,Java言語全体で,コメントの内容が生成されるコードに影響を与える唯一の場所とする。タグ @deprecated は,常に利用者に好ましい置換えを提示することが望ましい。次に例を示す。

    /**
      * @deprecated	This call has been replaced with dwishm
      * @see dwishm
      */
    public void dwim() { /*...*/ }
キーワード transient は,Java 1.1 では意味が定義された。A.5.2を参照すること。

配列を new するとき,配列の内容を初期化可能とする。例えば,文字列の配列を作成するための柔軟な方法を次に示す。

    String[] martians = new String[] {
			    "Gidney", "Cloyd"
			};

A.4 スレッド

将来の機能としていた割込み機構が Java 1.1 では実装された。

A.5 入出力

A.5.1 国際化

完全な国際化文字の問題を処理するために,多くの新しい入出力クラスを追加した。元のクラスは,ISO-Latin-1 8ビット文字のみで動作した(例えば, InputStream.read は, int について16ビットではなく8ビットを返した)。最大の変化は,PrintStream が使用しないことが望ましいクラスとしたことである。これは,このクラスが ISO-Latin-1 でだけ使用可能と考えられるからである。新しいクラスは, PrintWriter と呼ばれ,低レベルバイト書出し以外の PrintStream のメソッドすべてを提供する。PrintStream のメソッド print 及び println を使った既存のコードは,出力を局所文字集合に変換することとする。(使用しないことが望ましい,という大量の警告が出力されるのを防ぐために,PrintStream のコンストラクタだけに警告する。)

PrintStream の自動掃出しは整理された。自動掃出しを設定すれば,バイト配列の write がするように,出力内における任意の場所の改行が掃出しを引き起こす。自動掃出しを設定しなければ,自動掃出しは行わない。

PrintWriter は抽象クラス Writer のサブクラスとする。これは,国際化を理解するクラス OutputStream と並列に動作する。抽象クラス ReaderInputStream と並列に動作する。国際化された入出力に対していくつかの新しいクラス Reader 及び Writer が存在する。

フィールドSystem.inSystem.out 及び System.err は,セキュリティの理由で Java 1.1 では最終とする。そこで,これらのフィールドを修正するコードは動作しない。

新しいパッケージ java.text は,国際化テキストを構文解析し生成するのに有用な多くのクラスを含む。つまり,日付情報及び数字形式,現地依存の方法での文字列の比較及び並替え,現地語テキストの分離並びにその他の現地依存の入出力に対するクラスを含む。

A.5.2 オブジェクト整列化

ストリーム ObjectInputStream 及び ObjectOutputStream を使って,オブジェクト及びオブジェクトグラフ全体の読込み及び書出しを可能とする。writeObject を使って ObjectOutputStream に書き出したオブジェクトは,readObject を使って ObjectInputStream によって読み込んだときに,元のオブジェクトの完全なコピーを作成するバイトストリームを生成する。そのようなバイトストリームを作成する過程を 整列化(serialization) と呼ぶ。整列化されたコピーは完全なものとする。つまり,オブジェクトグラフの全体を整列化可能とし,生成されたバイトを非整列化(deserialize) するとき,元のグラフの完全なコピーを得る。二つ以上のオブジェクトが元のグラフ内で一つの特定のオブジェクトを参照していれば,非整列化されたコピーは,その同じ特定のオブジェクトのコピーを参照する二つ以上のオブジェクトのコピーをもつ。

バイトストリームは,私的フィールドを含む,整列化されたオブジェクトの状態を符号化する。そこで,任意の整列化可能オブジェクトは,私的フィールドの値がオブジェクトを整列化し生成したバイト列を読む者に調査されることを可能とする。プログラマの中には, private 宣言されたフィールドを秘密のものと考えていて,整列化の方法で値が提示されることを喜ばない者もいる。このために,オブジェクトがインタフェース Serializable を実装しなければ,オブジェクトは整列化可能としない。Serializable は,単にオブジェクトを整列化可能と記す空のインタフェースとする。デフォルト整列化機構は,単にオブジェクトの非静的及び非一時的フィールドを書き出す。これを,メソッド readObject 及び writeObject を提供することによって上書き可能とする。

インタフェース Serializable のサブインタフェースとするインタフェース Externalizable を代わりに実装するクラスは整列化可能だが,専用のメソッド readExternal 及び writeExternal を提供しなければならない。デフォルト整列化は使用しない。

A.6 ツール群

A.6.1 資源現地化

いくつかの新しいツール群を現地化のために追加した。新しいクラス Locale は,利用者が好む言語及びそれ以外の特性を定義するための特別な現地情報を記述する。利用者が好む現地情報に基づいた(利用者に表示するかもしれないメッセージのような)資源の集合を専用化するために,スーパクラス ResourceBundle を提供する。次のような ResourceBundle の部分型もいくつか提供する。例えば,ResourceBundle に対して資源及びその資源に対するキーのリストを簡潔に与えなければならないが,その単純な実装を提供する抽象クラス ListResourceBundle 及びキー付きの資源を含むファイルを使用する PropertyResourceBundle とする。

A.6.2 日付及び時刻

クラス Date の機能は,時間の種々計算を行うことが可能なより豊富なシステムへと分離した。現在,オブジェクト Date は,ミリ秒の大きさでだけ時刻の特定の瞬間を表現する。これ以外のコンストラクタ及びメソッドは,以前は二つの他の義務,つまり,年,日,時間,分及び秒の値としての時刻の文字列を整形すること及び時刻の瞬間を見せること,を果たしていた。これらすべてのメソッドは,次のもので置き換えて,使用しないことが望ましい。

これらの抽象クラスは柔軟性を可能とするが,ほとんどの人は,世界の大部分及び国際的取引で使用されるグレゴリオ暦での作業を必要とする。そこで Java 1.1 では次のものも提供する。

    class CurrentYear {
	public static void main(String[] args) {
	    GregorianCalendar now = new GregorianCalendar();
	    int year = now.get(Calendar.YEAR);
	    System.out.println("The year is " + year);
	}
    }

A.7 型をもったプログラミング

A.7.1 自己反映性

パッケージ java.lang.reflect は,Java についての自己反映性(reflection) 機構を提供する。これは十分にクラスを調査するためのツールとする。オブジェクト Class は,すべての公開(public)メソッド及び関係するクラスのフィールドを返却可能とする。メソッドを呼び出すためにオブジェクト Method を使用し,フィールドの値を獲得及び設定するためにオブジェクト Field を使用することが可能とする。オブジェクト Class は,非公開メンバも含むすべてのメンバのリストを返却可能とするが,普通,セキュリティ制限のためにこれを禁止する。

Java 言語にとって自然な他のツールで十分なときに,自己反映性を使う誘惑に惑わされないことが望ましい。例えば,他の言語で関数ポインタを使用することになれていると,オブジェクト Method を代わりに使おうと思ってしまうが,普通は,必要な動作を実行するオブジェクトを実装するインタフェースのようなオブジェクト指向ツールを使う方がよい。自己反映性は,デバッガ及びクラスブラウザのような言語ツールで使用することを意図している。

A.7.2 ラッパークラス

二つのラッパークラス,Short 及び Byte が追加された。これらは Number の部分型とする。新しいクラス Void も完全を期すために追加された。これは,返却型 void を表現するために自己反映性メソッドで使用する。

A.7.3 名前付きクラスのためのクラスオブジェクトの獲得

キーワード class の新しい使用法として,与えられた型に対するオブジェクト Class を獲得可能とする。次に例を示す。

    Class threadClass = Thread.class;
    Class intClass = int.class;
    Class voidClass = void.class;

A.8 ネイティブメソッド

Java メソッドをCで実装するための API は,現在完全に違っている。マッピングは正規化し,Java 仮想計算機の特別な実装とはほとんど関係しない。ネイティブメソッド(native method) マッピングに対する一般的な注釈は,現在でも意味があるが,特定の詳細事項は,今でも提供されているとはいえ,使用しないことが望ましい。新しい Java ネイティブインタフェース(Java Native Interface, JNI) は,学習及び使用することが非常に簡単となっている。

A.9 新しいパッケージ

Java 1.1 は,次のいくつかの新しいパッケージをもつ。


目次 | |