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

7. パッケージ

Java プログラムは,パッケージの集合で構成する。各パッケージは,型に対する名前の独自の集合をもつことで,名前の衝突を防ぐのを支援する。最上位の型は,publicと宣言した場合に限り,それを宣言しているパッケージの外部からアクセス可能とする(6.6)

パッケージの名前付けの構造は階層的とする(7.1)。パッケージのメンバは,そのパッケージのコンパイル単位内で宣言した,クラス及びインタフェース型(7.6),並びにそれ自体がコンパイル単位及び下位パッケージを含んでもよい下位パッケージとする。

パッケージは,ファイルシステム(7.2.1)又はデータベース(7.2.2)に格納できる。ファイルシステムに格納するパッケージは,単純な実装がクラスをたやすく検出できるように,コンパイル単位の構成に制約をもつ。

一つのパッケージは,複数のコンパイル単位で構成する(7.3)。コンパイル単位は,そのパッケージで宣言したすべての型に自動的にアクセス可能とし,さらにあらかじめ定義されたパッケージ java.lang で宣言したすべての public な型を自動的にインポートする。

小規模なプログラム及び暫定的な開発では,パッケージに名前を付けなかったり(7.4.2),単純名を用いることもできるが,Javaコードを広く配布する場合は,一意なパッケージ名を選択することが望ましい(7.7)。これによって,二つの開発グループが偶然同じパッケージ名を使用し,それらのパッケージを後に一つのプログラムで使用する場合に発生する名前の衝突を防ぐことができる。

7.1 パッケージのメンバ

パッケージのメンバは,下位パッケージ及び,パッケージのすべてのコンパイル単位(7.3)で宣言された,すべての最上位の(7.6)クラス(8)及び最上位のインタフェース(9)とする。

例えば,Javaアプリケーションプログラムインタフェースでは,次のようになっている。

パッケージの完全限定名(6.7)P とし,QP の下位パッケージとすれば,P.Q は下位パッケージの完全限定名とする。

パッケージは,同じ名前の二つのメンバを含んではならない。そうでなければ,コンパイル時エラーを生じる。

例を次に示す。

パッケージの階層化された名前付け構造は,関係するパッケージを慣用的な形式で構成するのに便利であることを意図しているが,パッケージ内で宣言した最上位の型(7.6)と同じ単純名をもつ下位パッケージの禁止という点を除けば重要ではない。oliver という名前のパッケージ及び oliver.twist という名前の別のパッケージには特別なアクセス関係は存在せず,evelyn.wood という名前のパッケージ及びevelyn.augh という名前のパッケージの間にも特別なアクセス関係は存在しない。例えば,oliver.twist という名前のパッケージ内のコードが,パッケージ oliver 内で宣言した型に,他のパッケージ内のコードよりもアクセスしやすいということはない。

7.2 パッケージのホスト支援

各ホストは,パッケージ,コンパイル単位及び下位パッケージの生成方法及び格納方法,並びに,特定のコンパイルにおいてどのコンパイル単位が観測可能(7.3)であるかを決定する。

コンパイル単位の観測可能性が,どのパッケージが観測可能であるか,及びどのパッケージが有効範囲内なのかを決定する。

Javaプラットフォームの単純な処理系では,パッケージを局所的なファイルシステムに格納してもよい。他の処理系では,Javaのソースコード及び(又は)バイナリコードを,分散ファイルシステム又はデータベースの何らかの形式に格納してもよい。

7.2.1 ファイルシステム内のパッケージの格納

極めて簡単な例として,一つのシステム上での,すべてのパッケージ,ソース及びバイトコードが,一つのディレクトリ及びその下位ディレクトリに格納されているとする。このディレクトリの各々の直下の下位ディレクトリは,最上位のパッケージ,つまり完全限定名が一つの単純名から構成されるものを示す。ディレクトリが,次に示す直下の下位ディレクトリを含むとする。

com
gls
jag
java
wnj
ディレクトリ java は,Java アプリケーションプログラムインタフェースパッケージを含む。ディレクトリjaggls 及び wnj は,この規定の三人の著者が,個人使用及び小グループ内で互いの共有のために作成したパッケージを含む。ディレクトリcom には,パッケージに一意な名前を付けるために7.7で説明する規約を使った,会社から調達したパッケージを含んでいる。

さらに,ディレクトリ java は,恐らく少なくとも次の下位ディレクトリを含んでいる。

applet	
awt
io
lang
net
util
これらは,Javaアプリケーションプログラミングインタフェースの一部として定義されたパッケージ java.appletjava.awtjava.iojava.langjava.net 及び java.util に対応する。

さらに,ディレクトリ util の中を見れば,次のファイルを見つけるだろう。

BitSet.java				Observable.java
BitSet.class				Observable.class
Date.java				Observer.java
Date.class				Observer.class
...
.java ファイルは,一つのクラス又はインタフェースの定義を含む一つのコンパイル単位(7.3)のソースを含み,対応する .class ファイルがコンパイルしたバイナリ形式を含む。

この単純なパッケージ構成において,Javaプラットフォームの処理系によっては,パッケージ名の構成要素を連結し,ファイル名の分離子(ディレクトリ表示子)を隣接する構成要素間に挟んで,パッケージ名をパス名に変換する。

例えば,この単純な構成をUNIXシステムで用いる場合,ファイル名の分離子は / なので,次のパッケージ名,

jag.scrabble.board
は,次のディレクトリ名へと変換される。

jag/scrabble/board
そして,

com.sun.sunsoft.DOE
は次のディレクトリ名へと変換される。

com/sun/sunsoft/DOE

ファイル名にASCII文字しか許さないシステム上でのUnicode文字のように,パッケージ名の構成要素又はクラス名が,ホストのファイルシステムでの通常のディレクトリ名では正しく出現できない文字を含むかもしれない。便宜的に,その文字は,\uxxxx エスケープ(3.3)と同じように,例えば文字 @ にその文字の数値を与える4桁の16進数字を続けることで,エスケープできる。このとき次のパッケージ名
children.activities.crafts.papierM\u00e2ch\u00e9
は,すべてUnicode文字を使って次のように書くことができる。

children.activities.crafts.papierMâché
さらに,これは次のディレクトリ名に写像される。

children/activities/crafts/papierM@00e2ch@00e9
文字 @ がホストのファイルシステムで有効でない文字ならば,識別子として有効でない他の文字を代わりに用いることも可能とする。

7.2.2 データベース内のパッケージの格納

ホストシステムは,パッケージ並びにそれらのコンパイル単位及び下位パッケージを,データベース内に格納してもよい。

そのようなデータベースが,ファイルに基づいた処理系におけるコンパイル単位上のオプションの制約(7.6)を強要してはならない。例えば,パッケージを格納するためにデータベースを使用するシステムは,コンパイル単位ごとに一つの public なクラス又はインタフェースの最大数を制限する必要はない。

ただし,データベースを使用するシステムは,ファイルに基づいた処理系へとエクスポートするために,プログラムをこの制約に従った形式に変換する方法を提供しなければならない。

7.3 コンパイル単位

CompilationUnitは,Javaプログラムの構文文法(2.3)の目標記号(2.1)とする。コンパイル単位は,次の生成規則で定義する。

別のコンパイル単位で宣言した型は,循環的に相互に依存可能とする。Javaコンパイラは,それらの型すべてを同時にコンパイルするように処理しなければならない。

コンパイル単位(compilation unit) は,次の三つの部分で構成される。ただし,各部分は省略してもよい。

どのコンパイル単位が観測可能(observable)であるかは,ホストシステムにより決定される。しかし,パッケージ java とその下位パッケージ lang 及び io は常に観測可能でなければならない。コンパイル単位の観測可能性はパッケージの観測可能性(7.4.3)に影響を及ぼす。

7.5.3に記述するように,すべてのコンパイル単位は,あらかじめ定義されたパッケージ java.lang 内で宣言したすべての public な型名を,自動的及び暗黙的にインポートし,それらの型の名前は単純名として使用できる。

7.4 パッケージ宣言

パッケージ宣言は,コンパイル単位内に出現し,そのコンパイル単位が属するパッケージを示す。

7.4.1 名前付きパッケージ

コンパイル単位内の パッケージ宣言(package declaration) は,コンパイル単位が属するパッケージの名前(6.2)を指定する。

パッケージ宣言内で用いるパッケージ名は,パッケージの完全限定名(6.7)でなければならない。

7.4.2 名前なしパッケージ

パッケージ宣言をもたないコンパイル単位は,名前なしパッケージの一部とする。

パッケージ宣言の構文は常に名前付きの最上位のパッケージへの参照を含まなければならないため,名前なしパッケージは下位パッケージをもつことができない点に注意すること。

例えば,次のコンパイル単位を考える。

class FirstCall {
	public static void main(String[] args) {
		System.out.println("Mr. Watson, come here. "
						+ "I want you.");
	}
}
これは,非常に単純なコンパイル単位を,名前なしパッケージの一部として定義する。

Javaプラットフォームの処理系は,少なくとも一つの名前なしパッケージを提供しなければならない。システムは複数の名前なしパッケージを提供してもよいが,これは必要とはしない。各々の名前なしパッケージ内にどのコンパイル単位が存在するかは,ホストシステムが決定する。

パッケージを格納するのに階層型のファイルシステムを使用するJavaプラットフォームの処理系では,名前なしパッケージを各ディレクトリに関連付けることを典型的な方法とする。ある時点で観測可能な名前なしパッケージは一つだけ,つまり"現在の作業ディレクトリ"に関連付けられたパッケージとする。"現在の作業ディレクトリ"の正確な意味は,ホストシステムに依存する。

Javaプラットフォームでは名前なしパッケージを,主として,小さな若しくは一時的なアプリケーションの開発時に,又は開発の初期段階に便利なように提供する。

7.4.3 パッケージの観測可能性

パッケージは次のいずれかの場合に限り必ず観測可能 (observable) とする。

上記の規則及び観測可能なコンパイル単位の要件より,パッケージ javajava.lang,及び java.io が常に観測可能であると結論付けることができる。

7.4.4 パッケージ宣言の有効範囲

観測可能な(7.4.3)最上位のパッケージの宣言の有効範囲は,すべての観測可能なコンパイル単位(7.3)とする。観測可能でないパッケージの宣言が有効範囲に入ることはない。下位パッケージ宣言が有効範囲に入ることはない。

パッケージ javaは常に有効範囲にあることになる (6.3)

パッケージ宣言は決して他の宣言をおおい隠すことはない。

7.5 インポート宣言

インポート宣言(import declaration) は,指定した型を,一つの識別子からなる単純名(6.2)で参照できるようにする。適切な import 宣言を使用せずに,他のパッケージで宣言した型を参照する唯一の方法は,その完全限定名(6.7)を使用することとする。

単一の型インポート宣言(7.5.1)は,その正準名を記述することで一つの型をインポートする。要求時の型インポート宣言(7.5.2)は,指定した型又はパッケージのすべてのアクセス可能な型を必要に応じてインポートする。

単一の型インポート宣言(7.5.1)又は要求時の型インポート宣言(7.5.2)でインポートされた型の有効範囲は,インポート宣言が存在するコンパイル単位の中のすべてのクラス及びインタフェースの型宣言(7.6)とする。

import 宣言は,実際に import 宣言を含むコンパイル単位内でだけ,単純名によって型を使用可能とする。明示的にインポートする要素の有効範囲には,現在のコンパイル単位の package 文及び他の import 宣言,並びに同じパッケージ内の他のコンパイル単位を含まない。説明的な例としては7.5.4を参照すること。

7.5.1 単一の型インポート宣言

単一の型インポート宣言(single-type-import declaration) は,正準名を与えて単一の型をインポートし,単一の型インポート宣言が存在するコンパイル単位のクラス宣言及びインタフェース宣言内で,単純名を使用可能とする。

TypeName は,クラス又はインタフェース型の正準名でなければならない。指定した型が存在しなければ,コンパイル時エラーが発生する。指定した型はアクセス可能(6.6)でなければならない。そうでないときには,コンパイル時エラーが発生する。

パッケージ p のコンパイル単位 c 内で,n という名前の型をインポートする単一の型インポート宣言 d は,c の中で次の宣言をおおい隠す。

次に例を示す。

import java.util.Vector;
この例では,単純名 Vector は,コンパイル単位内のクラス及びインタフェース宣言内で利用可能とする。そこで,単純名 Vector は,同じ名前をもつフィールド,仮引数,局所変数又は入れ子型の宣言によっておおい隠されない(6.3.1),又は不明瞭とされない(6.3.2),すべての場所でパッケージ java.util 内の型 Vector を参照する。

同じコンパイル単位内の二つの単一の型インポート宣言が,同じ単純名をもつ型をインポートしようとすれば,二つの型が同じ型でなければ,コンパイル時エラーが発生する。同じ型の場合は,重複する宣言は無視する。現在のコンパイル単位内で,要求時の型インポート宣言(7.5.2)以外の方法で同じ名前をもつ他の最上位の型を宣言すれば,コンパイル時エラーが発生する。

次にプログラム例を示す。

import java.util.Vector;
class Vector { Object[] vec; }
この例は,Vector の二重宣言のために,コンパイル時エラーを引き起こす。同様に,次の例もコンパイル時エラーを引き起こす。

import java.util.Vector;
import myVector.Vector;
この例では,myVector が次のコンパイル単位を含むパッケージとする。

package myVector;
public class Vector { Object[] vec; }
コンパイラは,バイナリ名(13.1)で型を記憶する。

import 文は,下位パッケージをインポートできず,型だけをインポート可能とする。例えば,次の例に示すように,型 java.util.Random を参照するために java.util をインポートし util.Random という名前を使用しようとしても動作しない。

import java.util;		// incorrect: compile-time error
class Test { util.Random generator; }

7.5.2 要求時の型インポート宣言

要求時の型インポート宣言(type-import-on-demand declaration) は,正準名によって指定された型又はパッケージ内で宣言したすべてのアクセス可能な(6.6)型を,必要に応じてインポート可能とする。

要求時の型インポート宣言で指定した型又はパッケージが,アクセス不可能ならば,コンパイル時エラーとする。同じコンパイル単位における二つ以上の要求時の型インポート宣言が,同じパッケージを指定してもよい。その効果は,一つだけ宣言が存在する場合と同じとする。現在のパッケージ又は java.lang を,要求時の型インポート宣言で指定することは,コンパイル時エラーとはしない。そのような場合,要求時の型インポート宣言は無視する。

要求時の型インポート宣言は決して他の宣言をおおい隠すことはない。

次に例を示す。

import java.util.*;
この例では,コンパイル単位のクラス宣言及びインタフェース宣言において,パッケージ java.utilpublic と宣言したすべての型の単純名が利用可能となる。そこで,単純名 Vectorは,型宣言がおおい隠される(6.3.1)か不明瞭(6.3.2)とされない限り,コンパイル単位内のすべての場所でパッケージ java.util 内の型 Vector を参照する。宣言は,単純名を Vector とする型の単一の型インポート宣言,コンパイル単位が属するパッケージ内で Vector という名前で宣言した型,又は入れ子のクラス又はインタフェースによりおおい隠される。宣言は,Vector という名前のフィールド, 仮引数又は局所変数の宣言によって不明瞭にされる(こうした条件が発生することは普通ではない)。

7.5.3 自動インポート

各コンパイル単位は,あらゆる package 文の直後の各コンパイル単位の先頭に,

import java.lang.*;
という宣言が,存在するかのように,あらかじめ定義されたパッケージ java.lang で宣言した各 public な型名を自動的にインポートする。

7.5.4 まれな例

6.8で記述する名前付け規約では,パッケージと型の名前とは通常違うものとする。それにもかかわらず,次の作為的な例では,規約に反する名前付けをされたパッケージ Vector が存在する。それが,Mosquito という名前の public クラスを宣言する。

package Vector;
public class Mosquito { int capacity; }
コンパイル単位は次のとおりとする。

package strange.example;
import java.util.Vector;
import Vector.Mosquito;
class Test {
	public static void main(String[] args) {
		System.out.println(new Vector().getClass());
		System.out.println(new Mosquito().getClass());
	}
}
パッケージ java.util からクラス Vector をインポートする単一の型インポート宣言(7.5.1)は,パッケージ名 Vector がそれに続く import 宣言で出現し,正しく認識されることを妨げない。この例はコンパイル可能で,次の出力を生成する。

class java.util.Vector
class Vector.Mosquito

7.6 最上位の型宣言

最上位の型宣言(type declaration)は,最上位のクラス型(8)又はインタフェース型(9)を宣言する。

デフォルトでは,パッケージで宣言した最上位の型は,そのパッケージのコンパイル単位内でだけアクセス可能とする。しかし,他のパッケージのコードからその型をアクセス可能とするために,型を public として宣言してもよい(6.68.1.19.1.1)。

最上位の型の有効範囲は,その最上位の型が宣言されているパッケージ内のすべての型宣言とする。

Tという名前の最上位の型が,完全限定名がPであるパッケージのコンパイル単位で宣言された場合,その型の完全限定名はP.Tとする。型が名前なしパッケージ(7.4.2)で宣言された場合,その型は完全限定名としてTをもつ。

次の例で示す。

package wnj.points;
class Point { int x, y; }
この例では,クラス Point の完全限定名は wnj.points.Point である。

Javaプラットフォームの処理系は,バイナリ名(13.1)でパッケージ内の型を記憶しなければならない。型の名前付けの様々な方法は,その名前が同じ型を参照していることを確認するために,バイナリ名に展開しなければならない。

例えば,コンパイル単位が次の単一の型インポート宣言(7.5.1)を含む場合を考える。

import java.util.Vector;
コンパイル単位内では,単純名 Vector 及び完全限定名 java.util.Vector は同じ型を参照する。

パッケージがファイルシステム(7.2.1)に格納されるとき,ホストシステムは,次のいずれかが真の場合は,型名及び(.java 又は .jav のような)拡張子から構成される名前でファイル内にその型を見つけられなければ,コンパイル時エラーとする制約を課すことができる。

この制約は,コンパイル単位ごとにそうした型が高々一つ存在しなければならないことを意味する。この制約によって,Javaプログラム言語のコンパイラ又はJava仮想計算機の処理系は,パッケージ内で,名前付きクラスを容易に見つけられる。例えば,publicな型 wet.sprocket.Toad のソースコードは,ディレクトリ wet/sprocket のファイル Toad.java で見つかり,それに対応するオブジェクトコードは,同じディレクトリ内のファイル Toad.class で見つかる。

パッケージがデータベースに格納されるとき(7.2.2),ホストシステムはそうした制約を課してはならない。

実際には,それが public かどうか,又は他のコンパイル単位内のコードから参照されているかどうかにかかわらず,多くのプログラマは,それぞれのクラス又はインタフェース型をそれ自体のコンパイル単位に入れている。 最上位の型の名前が,同じパッケージ内で宣言された他の最上位のクラス又はインタフェース型の名前として現れた場合(7.6)は,コンパイル時エラーとする。

最上位の型の名前が,型宣言を含むコンパイル単位(7.3)内の単一の型インポート宣言(7.5.1)でまた宣言された場合は,コンパイル時エラーとする。

次に例を示す。

class Point { int x, y; }
この例では,クラス Point がパッケージ文をもたないコンパイル単位で宣言されており,Point 自体が完全限定名となる。

package vista;
class Point { int x, y; }
この例では,クラス Point の完全限定名は vista.Point となる。(パッケージ名 vista は局所的又は個人的利用に適している。パッケージが広く配布されることを意図されているならば,一意なパッケージ名(7.7)を付けるのがよい。)

package test;
import java.util.Vector;
class Point {
	int x, y;
}
interface Point {			// compile-time error #1
	int getR();
	int getTheta();
}
class Vector { Point[] pts; }	// compile-time error #2
この例では,最初のコンパイル時エラーが,名前 Point を同じパッケージの中でクラスとインタフェースとで二重に宣言していることによって発生する。コンパイル時に検出される二番目のエラーは,名前 Vector をクラス型宣言と単一の型インポート宣言とで宣言を試みている点である。

しかしながら,クラスの名前が,そのクラス宣言を含むコンパイル単位(7.3)内の要求時の型インポート宣言(7.5.2)によってインポートされるかもしれない型の名前と同じであってもエラーとならない。次に例を示す。

package test;
import java.util.*;
class Vector { Point[] pts; }	// not a compile-time error
この例では,クラス java.util.Vector が存在するにも関わらず,クラス Vector の宣言は許される。このコンパイル単位内では,単純名 Vector はクラス java.util.Vector (完全限定名によってのみ,このコンパイル単位内で参照可能) ではなくクラス test.Vector を参照する。

他の例を次に示す。

package points;
class Point {
	int x, y;			// coordinates
	PointColor color;		// color of this point
	Point next;			// next point with this color
	static int nPoints;
}
class PointColor {
	Point first;			// first point with this color
	PointColor(int color) {
		this.color = color;
	}
	private int color;		// color components
}
このコンパイル単位はクラスのメンバ宣言に互いのクラスをもつ二つのクラスを定義する。クラス型 Point と PointColor は有効範囲としてパッケージ points のすべての型宣言をもち,更に現在のコンパイル単位内にすべてをもつため,この例は正しくコンパイルされる。すなわち,前方参照することは問題ではない。

最上位の型宣言が, protected,private 又は static のアクセス修飾子のうちの一つでも含むならば,コンパイル時エラーとする。

7.7 一意なパッケージ名

広く配布されるパッケージについては,開発者は,一意なパッケージ名(unique package names) を選択して,二つの公開されたパッケージが同じ名前をもつ可能性を排除する手順を踏むことが望ましい。これは,パッケージを容易及び自動的にインストール及び管理可能とする。7.7では,一意なパッケージ名を生成するための推奨される規約を規定する。Javaプラットフォームの処理系は,局所的及び暫定的なパッケージ名を,7.7で記述する一意な名前の書式にパッケージの集合を変換する自動的な方法を提供することが望ましい。

一意なパッケージ名を使用していなければ,名前の衝突が生じたどちらかのプログラムを開発してからはるかに時間が経過した時点で,パッケージ名の衝突が生じる可能性がある。この場合,ユーザ又はプログラマにとって,解決が困難又は不可能な状況が生じる。プログラムを一見しただけでは見当もつかないような制約された相互作用をしているパッケージの集まりにおいて,クラス ClassLoader を使うことによって,同じ名前をもったパッケージを互いに使い分けることができる。

一意なパッケージ名を生成するには,まず,sun.com のようなインターネットドメイン名を取得する(あるいは,それをもっている組織に所属する)。その後,この名前を構成要素の順序を逆にして (この例では,com.sun として),パッケージ名の前置詞として使用する。それ以降の名前は,パッケージ名を管理するための組織内で開発された規約を使用する。

インターネットのドメイン名が有効なパッケージ名ではない場合がある。そのような場合に推奨される規約を示す。

そうした規約では,ディレクトリ名の構成要素を,部,課,プロジェクト,マシン又はログインの名前に指定するかもしれない。次に例を示す。
com.sun.sunsoft.DOE
com.sun.java.jag.scrabble
com.apple.quicktime.v2
edu.cmu.cs.bovik.cheese
gov.whitehouse.socks.mousefinder
一意なパッケージ名の最初の構成要素は,常にすべて小文字のASCII文字で書き,現時点では comedugovmilnet 又は org という最上位のドメイン名の一つ,又はISO 3166:1981で規定された英字2文字の国名コードの一つとする。詳細については,http://www.ietf.org/rfc.html から取得できるドキュメント,例えば,rfc920.txt 及び rfc1032.txt を参照のこと。

パッケージの名前は,インターネットにおいてパッケージが格納されている場所についての何らかの情報を示すものではない。例えば,edu.cmu.cs.bovik.cheese という名前のパッケージが,インターネットアドレス cmu.educs.cmu.edu 又は bovik.cs.cmu.edu から必ず入手できるというわけではない。一意なパッケージ名を生成するための推奨される規約は,パッケージ名のために独自の登録簿を作る代りとして,既存の広く知られた一意な名前の登録簿の上にパッケージ名前付け規約を追加しているだけである。

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