目次 | 前 | 次 | 索引 | Java言語規定 第2版 |
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)。これによって,二つの開発グループが偶然同じパッケージ名を使用し,それらのパッケージを後に一つのプログラムで使用する場合に発生する名前の衝突を防ぐことができる。
例えば,Javaアプリケーションプログラムインタフェースでは,次のようになっている。
java
は,下位パッケージ awt
,applet
,io
,lang
,net
及び util
をもつが,コンパイル単位はもたない。
java.awt
は image
という下位パッケージをもち,さらに,クラス及びインタフェース型の宣言を含む多くのコンパイル単位をもつ。
.
Q は下位パッケージの完全限定名とする。パッケージは,同じ名前の二つのメンバを含んではならない。そうでなければ,コンパイル時エラーを生じる。
java.awt
は,下位パッケージ image
をもつので,image
という名前のクラス又はインタフェース型の宣言を含むことはできない(そして含んでいない)。
mouse
という名前のパッケージが存在し,そのパッケージ内にメンバ型 Button
(mouse.Button
として参照する)が存在すれば,mouse.Button
又は mouse.Button.Click
という完全限定名をもつパッケージは存在できない。
com.sun.java.jag
が型の完全限定名ならば,完全限定名を com.sun.java.jag
又は com.sun.java.jag.scrabble
とするパッケージは存在できない。
oliver
という名前のパッケージ及び oliver.twist
という名前の別のパッケージには特別なアクセス関係は存在せず,evelyn.wood
という名前のパッケージ及びevelyn.augh
という名前のパッケージの間にも特別なアクセス関係は存在しない。例えば,oliver.twist
という名前のパッケージ内のコードが,パッケージ oliver
内で宣言した型に,他のパッケージ内のコードよりもアクセスしやすいということはない。
コンパイル単位の観測可能性が,どのパッケージが観測可能であるか,及びどのパッケージが有効範囲内なのかを決定する。
Javaプラットフォームの単純な処理系では,パッケージを局所的なファイルシステムに格納してもよい。他の処理系では,Javaのソースコード及び(又は)バイナリコードを,分散ファイルシステム又はデータベースの何らかの形式に格納してもよい。
ディレクトリcom gls jag java wnj
java
は,Java アプリケーションプログラムインタフェースパッケージを含む。ディレクトリjag
,gls
及び wnj
は,この規定の三人の著者が,個人使用及び小グループ内で互いの共有のために作成したパッケージを含む。ディレクトリcom
には,パッケージに一意な名前を付けるために7.7で説明する規約を使った,会社から調達したパッケージを含んでいる。
さらに,ディレクトリ java
は,恐らく少なくとも次の下位ディレクトリを含んでいる。
これらは,Javaアプリケーションプログラミングインタフェースの一部として定義されたパッケージapplet awt io lang net util
java.applet
,java.awt
,java.io
,java.lang
,java.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
ファイル名にASCII文字しか許さないシステム上でのUnicode文字のように,パッケージ名の構成要素又はクラス名が,ホストのファイルシステムでの通常のディレクトリ名では正しく出現できない文字を含むかもしれない。便宜的に,その文字は,com/sun/sunsoft/DOE
\u
xxxx エスケープ(3.3)と同じように,例えば文字 @
にその文字の数値を与える4桁の16進数字を続けることで,エスケープできる。このとき次のパッケージ名
は,すべてUnicode文字を使って次のように書くことができる。children.activities.crafts.papierM\u00e2ch\u00e9
さらに,これは次のディレクトリ名に写像される。children.activities.crafts.papierMâché
文字children/activities/crafts/papierM@00e2ch@00e9
@
がホストのファイルシステムで有効でない文字ならば,識別子として有効でない他の文字を代わりに用いることも可能とする。
そのようなデータベースが,ファイルに基づいた処理系におけるコンパイル単位上のオプションの制約(7.6)を強要してはならない。例えば,パッケージを格納するためにデータベースを使用するシステムは,コンパイル単位ごとに一つの public
なクラス又はインタフェースの最大数を制限する必要はない。
ただし,データベースを使用するシステムは,ファイルに基づいた処理系へとエクスポートするために,プログラムをこの制約に従った形式に変換する方法を提供しなければならない。
CompilationUnit: PackageDeclarationopt ImportDeclarationsopt TypeDeclarationsopt ImportDeclarations: ImportDeclaration ImportDeclarations別のコンパイル単位で宣言した型は,循環的に相互に依存可能とする。Javaコンパイラは,それらの型すべてを同時にコンパイルするように処理しなければならない。ImportDeclaration TypeDeclarations: TypeDeclaration TypeDeclarations
TypeDeclaration
コンパイル単位(compilation unit) は,次の三つの部分で構成される。ただし,各部分は省略してもよい。
package
宣言(7.4)。コンパイル単位が属するパッケージの完全限定名(6.7)を指定する。パッケージ宣言をもたないコンパイル単位は名前なしパッケージ(7.4.2)の一部とする。
import
宣言(7.5)。他のパッケージの型を単純名を使って参照可能とする。
java
とその下位パッケージ lang
及び io
は常に観測可能でなければならない。コンパイル単位の観測可能性はパッケージの観測可能性(7.4.3)に影響を及ぼす。
7.5.3に記述するように,すべてのコンパイル単位は,あらかじめ定義されたパッケージ java.lang
内で宣言したすべての public
な型名を,自動的及び暗黙的にインポートし,それらの型の名前は単純名として使用できる。
PackageDeclaration:パッケージ宣言内で用いるパッケージ名は,パッケージの完全限定名(6.7)でなければならない。package
PackageName;
パッケージ宣言の構文は常に名前付きの最上位のパッケージへの参照を含まなければならないため,名前なしパッケージは下位パッケージをもつことができない点に注意すること。
これは,非常に単純なコンパイル単位を,名前なしパッケージの一部として定義する。class FirstCall { public static void main(String[] args) { System.out.println("Mr. Watson, come here. " + "I want you."); } }
Javaプラットフォームの処理系は,少なくとも一つの名前なしパッケージを提供しなければならない。システムは複数の名前なしパッケージを提供してもよいが,これは必要とはしない。各々の名前なしパッケージ内にどのコンパイル単位が存在するかは,ホストシステムが決定する。
パッケージを格納するのに階層型のファイルシステムを使用するJavaプラットフォームの処理系では,名前なしパッケージを各ディレクトリに関連付けることを典型的な方法とする。ある時点で観測可能な名前なしパッケージは一つだけ,つまり"現在の作業ディレクトリ"に関連付けられたパッケージとする。"現在の作業ディレクトリ"の正確な意味は,ホストシステムに依存する。
Javaプラットフォームでは名前なしパッケージを,主として,小さな若しくは一時的なアプリケーションの開発時に,又は開発の初期段階に便利なように提供する。
上記の規則及び観測可能なコンパイル単位の要件より,パッケージ
java
,java.lang
,及び java.io
が常に観測可能であると結論付けることができる。
パッケージ java
は常に有効範囲にあることになる (6.3)。
import
宣言を使用せずに,他のパッケージで宣言した型を参照する唯一の方法は,その完全限定名(6.7)を使用することとする。
ImportDeclaration: SingleTypeImportDeclaration TypeImportOnDemandDeclaration単一の型インポート宣言(7.5.1)は,その正準名を記述することで一つの型をインポートする。要求時の型インポート宣言(7.5.2)は,指定した型又はパッケージのすべてのアクセス可能な型を必要に応じてインポートする。
単一の型インポート宣言(7.5.1)又は要求時の型インポート宣言(7.5.2)でインポートされた型の有効範囲は,インポート宣言が存在するコンパイル単位の中のすべてのクラス及びインタフェースの型宣言(7.6)とする。
import
宣言は,実際に import
宣言を含むコンパイル単位内でだけ,単純名によって型を使用可能とする。明示的にインポートする要素の有効範囲には,現在のコンパイル単位の
package
文及び他の import
宣言,並びに同じパッケージ内の他のコンパイル単位を含まない。説明的な例としては7.5.4を参照すること。
SingleTypeImportDeclaration:
import
TypeName ;
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
が次のコンパイル単位を含むパッケージとする。
コンパイラは,バイナリ名(13.1)で型を記憶する。package myVector; public class Vector { Object[] vec; }
import
文は,下位パッケージをインポートできず,型だけをインポート可能とする。例えば,次の例に示すように,型 java.util.Random
を参照するために java.util
をインポートし util.Random
という名前を使用しようとしても動作しない。
import java.util; // incorrect: compile-time error class Test { util.Random generator; }
TypeImportOnDemandDeclaration:要求時の型インポート宣言で指定した型又はパッケージが,アクセス不可能ならば,コンパイル時エラーとする。同じコンパイル単位における二つ以上の要求時の型インポート宣言が,同じパッケージを指定してもよい。その効果は,一つだけ宣言が存在する場合と同じとする。現在のパッケージ又はimport
PackageOrTypeName. * ;
java.lang
を,要求時の型インポート宣言で指定することは,コンパイル時エラーとはしない。そのような場合,要求時の型インポート宣言は無視する。要求時の型インポート宣言は決して他の宣言をおおい隠すことはない。
この例では,コンパイル単位のクラス宣言及びインタフェース宣言において,パッケージimport java.util.*;
java.util
で public
と宣言したすべての型の単純名が利用可能となる。そこで,単純名 Vector
は,型宣言がおおい隠される(6.3.1)か不明瞭(6.3.2)とされない限り,コンパイル単位内のすべての場所でパッケージ java.util
内の型 Vector
を参照する。宣言は,単純名を Vector
とする型の単一の型インポート宣言,コンパイル単位が属するパッケージ内で Vector
という名前で宣言した型,又は入れ子のクラス又はインタフェースによりおおい隠される。宣言は,Vector
という名前のフィールド, 仮引数又は局所変数の宣言によって不明瞭にされる(こうした条件が発生することは普通ではない)。package
文の直後の各コンパイル単位の先頭に,
という宣言が,存在するかのように,あらかじめ定義されたパッケージimport java.lang.*;
java.lang
で宣言した各 public
な型名を自動的にインポートする。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
TypeDeclaration:
ClassDeclaration
InterfaceDeclaration
;
デフォルトでは,パッケージで宣言した最上位の型は,そのパッケージのコンパイル単位内でだけアクセス可能とする。しかし,他のパッケージのコードからその型をアクセス可能とするために,型を public
として宣言してもよい(6.6,8.1.1,9.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)でまた宣言された場合は,コンパイル時エラーとする。
この例では,クラス Point がパッケージ文をもたないコンパイル単位で宣言されており,Point 自体が完全限定名となる。class Point { int x, y; }
この例では,クラス Point の完全限定名はpackage vista; class Point { int x, y; }
vista.Point
となる。(パッケージ名 vista は局所的又は個人的利用に適している。パッケージが広く配布されることを意図されているならば,一意なパッケージ名(7.7)を付けるのがよい。)この例では,最初のコンパイル時エラーが,名前 Point を同じパッケージの中でクラスとインタフェースとで二重に宣言していることによって発生する。コンパイル時に検出される二番目のエラーは,名前 Vector をクラス型宣言と単一の型インポート宣言とで宣言を試みている点である。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
しかしながら,クラスの名前が,そのクラス宣言を含むコンパイル単位(7.3)内の要求時の型インポート宣言(7.5.2)によってインポートされるかもしれない型の名前と同じであってもエラーとならない。次に例を示す。
この例では,クラス java.util.Vector が存在するにも関わらず,クラス Vector の宣言は許される。このコンパイル単位内では,単純名 Vector はクラス java.util.Vector (完全限定名によってのみ,このコンパイル単位内で参照可能) ではなくクラス test.Vector を参照する。package test; import java.util.*; class Vector { Point[] pts; } // not a compile-time error
このコンパイル単位はクラスのメンバ宣言に互いのクラスをもつ二つのクラスを定義する。クラス型 Point と PointColor は有効範囲としてパッケージ points のすべての型宣言をもち,更に現在のコンパイル単位内にすべてをもつため,この例は正しくコンパイルされる。すなわち,前方参照することは問題ではない。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 }
最上位の型宣言が, protected,private 又は static のアクセス修飾子のうちの一つでも含むならば,コンパイル時エラーとする。
一意なパッケージ名を使用していなければ,名前の衝突が生じたどちらかのプログラムを開発してからはるかに時間が経過した時点で,パッケージ名の衝突が生じる可能性がある。この場合,ユーザ又はプログラマにとって,解決が困難又は不可能な状況が生じる。プログラムを一見しただけでは見当もつかないような制約された相互作用をしているパッケージの集まりにおいて,クラス ClassLoader
を使うことによって,同じ名前をもったパッケージを互いに使い分けることができる。
一意なパッケージ名を生成するには,まず,sun.com
のようなインターネットドメイン名を取得する(あるいは,それをもっている組織に所属する)。その後,この名前を構成要素の順序を逆にして (この例では,com.sun
として),パッケージ名の前置詞として使用する。それ以降の名前は,パッケージ名を管理するための組織内で開発された規約を使用する。
インターネットのドメイン名が有効なパッケージ名ではない場合がある。そのような場合に推奨される規約を示す。
一意なパッケージ名の最初の構成要素は,常にすべて小文字のASCII文字で書き,現時点ではcom.sun.sunsoft.DOE com.sun.java.jag.scrabble com.apple.quicktime.v2 edu.cmu.cs.bovik.cheese gov.whitehouse.socks.mousefinder
com
,edu
,gov
,mil
,net
又は org
という最上位のドメイン名の一つ,又はISO 3166:1981で規定された英字2文字の国名コードの一つとする。詳細については,http://www.ietf.org/rfc.html
から取得できるドキュメント,例えば,rfc920.txt
及び rfc1032.txt
を参照のこと。
パッケージの名前は,インターネットにおいてパッケージが格納されている場所についての何らかの情報を示すものではない。例えば,edu.cmu.cs.bovik.cheese
という名前のパッケージが,インターネットアドレス cmu.edu
,cs.cmu.edu
又は bovik.cs.cmu.edu
から必ず入手できるというわけではない。一意なパッケージ名を生成するための推奨される規約は,パッケージ名のために独自の登録簿を作る代りとして,既存の広く知られた一意な名前の登録簿の上にパッケージ名前付け規約を追加しているだけである。
目次 | 前 | 次 | 索引 | Java言語規定 第2版 |