[???] / [Java FAQ] / [S017]
S017: パッケージ - package

[S017 Q-01]
Back
パッケージ(package)ってなんですか? [S017 A-01] 多数のクラスを機能、種別によってグループに分けるための仕組みです。 パッケージはディレクトリ構造のような階層によって表現されます。一般的にクラスファイルは、 パッケージと同一の階層をもつディレクトリ階層に格納されます。各クラスの完全な名称 (FQCN:fully-qualified class name) は各階層の名称を "." で連結したパッケージ名と クラス名によって表現されます。 例えば、java.util パッケージの Vector クラスを考えます。 この場合、下図のような階層に配置されます。 java/ | +- util/ | +- Vector.class パッケージには以下のような特徴があります。 ・名前空間はパッケージごとに独立 ・パッケージ内のクラスから、同一パッケージ内のアクセス修飾子 (public、protected、private)のない変数を使用することが可能 パッケージの特殊な場合として、package を指定しない場合にクラスが属する デフォルトパッケージがあります。
[S017 Q-02]
Back
自作のプログラムを公開したいのですが、パッケージ名はどのようにつけたら良いのでしょうか? [S017 A-02] 世界的に一意なパッケージ名を付けなければなりません。 指針は以下の URL に詳細があります。 The Java Language Specification, 7.7 Unique Package Names http://java.sun.com/docs/books/jls/second_edition/html/packages.doc.html#40169 世界的に一意なパッケージ名(Globally Unique Package Names)は 基本的にはドメイン名を元に決定することになります。 あなたの所属するドメインが my.domain.co.jp の場合、パッケージ名は jp.co.domain.my JP.co.domain.my から始まります。 (*)現在は、最初の書式が推奨されています。 もし独自のドメイン名を持っていない場合は、以下の URL にて パッケージ名登録サービスが行われています。 http://www.java-conf.gr.jp/wg_bof/package/ 参考記事[JavaHouse-Brewers:6405]
[S017 Q-03]
Back
インポートの際 "*" でパッケージをまるごと指定するのと、クラス名指定では違いがあるのでしょうか? [S017 A-03] 本質的な違いはありません。 ただし、前者の場合では、指定されるパッケージが大きい場合 コンパイル時にエラーが発生する、といった例もあるようです。 また前者には、ソース中に現れたクラスがどのパッケージ からインポートされているのかが特定しにくい、という面も ありますので、後者のようにクラスごとにインポートする ことをお勧めします。 参考記事[JavaHouse-Brewers:15723],[JavaHouse-Brewers:13783]
[S017 Q-04]
Back
パッケージの宣言をしていないクラスをインポートしたいのですが。 [S017 A-04] インポート宣言にクラス名を書きます。 例えば、あるディレクトリに次のようにクラスを配置したとします。 classes/ | +- A.class | +- test/ | +- B.class A.class はパッケージ指定なし、B.class はパッケージ test として定義 されています。 この場合、B.class から A.class を参照するには //B.java // デフォルトパッケージからのインポート package test; import A; public class B { ... } のようにインポートする必要があります。 もし、 import A; を記述しなかったら、A.class は test パッケージから検索されます。 従って、上記階層が classes/ | +- A.class | +- test/ | +- A.class | +- B.class のような構成となっている場合には、コンパイル時にエラーは出ませんので 注意が必要です。
[S017 Q-05]
Back
パッケージの指定をしないとどうなるのですか? [S017 A-05] デフォルトパッケージとなります。 デフォルトパッケージとは、 package 宣言によって、明示的に所属パッケージを指定しない場合に、その クラスが所属しているとみなされるパッケージです。 (*)無名パッケージ(Unnamed Packages)とも呼ばれます。 デフォルトパッケージもパッケージですので、S017-01 と同じことがいえます。
[S017 Q-06]
Back
パッケージを宣言したらコンパイルできなくなったのですが。 [S017 A-06] クラスパスが正しく設定されていないためです。 仮にパッケージを宣言する前が次のようなプログラムだったとします。 class Foo {} class Bar extends Foo {} ここで、パッケージ foobar を宣言します。 package foobar; class Foo {} package foobar; class Bar extends Foo {} これをコンパイルしようとするとコンパイルエラーが発生します。 これを解決するには次のような方法があります。 (1) javac の -d オプションを用いると指定したディレクトリの下に パッケージと同じ名前のディレクトリが作成され、その下にクラス ファイルが生成されます。 例) javac -d . Bar.java この場合、暗黙的に設定されるクラスパス(カレントディレクトリ)が 適用されるのでコンパイルできます。 (2) パッケージと同じ名前のディレクトリを作成し、ソースファイルを パッケージ名のディレクトリに移動します。ここで次のように コマンドを実行するとパッケージ名のディレクトリにクラスファイルが 生成されます。 例) javac foobar/Bar.java (1)同様、暗黙的に設定されるクラスパス(カレントディレクトリ)が 適用されるのでコンパイルできます。 (3) パッケージと同じ名前のディレクトリを作成し、ソースファイルを パッケージ名のディレクトリに移動します。ここでソースファイルと 同じディレクトリに移動して次のようにコマンドを実行すると このディレクトリにクラスファイルが生成されます。 例) javac -classpath .. Bar.java この場合、明示的にクラスパスを設定しているのでコンパイルできます。 参考記事[JavaHouse-Brewers:7625],[JavaHouse-Brewers:4071],[JavaHouse-Brewers:3178],[JavaHouse-Brewers:683]
[S017 Q-07]
Back
パッケージを宣言したら実行できなくなったのですが。 [S017 A-07] パッケージ名を指定していないかクラスパスの問題です。 ichinichi ディレクトリの下に asa ディレクトリを作成し、 asa に次のプログラムをコンパイルした Aisatu.class を置いたとします。 package asa; class Aisatu { public static void main(String[] args) { System.out.println("Good Morning !"); } } Aisatu.class を実行するには (1) ichinichi ディレクトリで java asa.Aisatu のように実行します。 (2) asa ディレクトリで java -cp .. asa.Aisatu のように実行します。
[S017 Q-08]
Back
既存パッケージの中のクラスを自作のものに置き換えたいのですが。 [S017 A-08] やむを得ない事情がない限り、やめるべきです。 JDK のクラスは契約事項として置き換えを禁止しています。
[S017 Q-09]
Back
JDK のライブラリのパッケージ名と同じ名前のパッケージのクラスを作成できますか? [S017 A-09] 作成することは可能ですが、お勧めできません。 理由は、クラスの追加もパッケージレベルでは改変と考えられるためです。 S017-08を参照してください。 参考記事[JavaHouse-Brewers:4341]
[S017 Q-10]
Back
デフォルトパッケージってなんですか? [S017 A-10] package 宣言によって、明示的に所属パッケージを指定しない場合に、その クラスが所属しているとみなされるパッケージです。 (*)無名パッケージ(Unnamed Packages)と同様 デフォルトパッケージもパッケージですので、S017-01 と同じことがいえます。
[S017 Q-11]
Back
パッケージを使う場合の CLASSPATH、CODEBASE の設定方法は? [S017 A-11] S017-06 を参照して下さい。
[S017 Q-12]
Back
パッケージ名に "-" が使えないのですが? パッケージ名に "interface" が使えないのですが? [S017 A-12] パッケージ名として使用できる文字は A から Z a から z 0 から 9 _ 及び $ です。 パッケージ名称の区切り文字は "." です。 加えて以下の制限があります。 各識別子は数字で始まってはいけません。 各識別子には Java の予約語は使用できません。 従って、"-" や "*" はパッケージ名には使用できませんし、 "interface" や "null" なども駄目です。 (*)より正確には、識別子(Identifier)に使用できる文字は 先頭文字については java.lang.Character.isJavaIdentifierStart(char) 先頭以外については java.lang.Character.isJavaIdentifierPart(char) がそれぞれ True となる文字です。 上記で記述できない名称の場合は、以下が推奨されます。 ・"01class" のように数字で始まる名称を使用したい。 先頭に "_" を付加して、"_01class" のようにする。 ・"interface" や "public" などの予約語を使用したい。 Java では大文字、小文字が区別されますので、"Interface" や "Public" などを使用する。 または、先頭に "_" を付加する。 ・特にドメイン名をパッケージ名に用いる場合に "-" がドメイン名 に含まれている. "-" を "_" に置き換える。 参考記事[JavaHouse-Brewers:7036],[JavaHouse-Brewers:7102]
[S017 Q-13]
Back
java.lang パッケージはインポートしていないのですが System.out.println() 等が使えるようです。なぜ? [S017 A-13] java.lang パッケージはシステムの動作に必要となるクラス群が格 納されているため、ほっておいてもインポートされた状態になるため です。
[S017 Q-14]
Back
パッケージのバージョンを管理したいのですが? [S017 A-14] Java 2 以降であればパッケージにバージョン情報を付加すること ができます。 例えば、2つのパッケージを1JAR ファイルにまとめてそれぞれに バージョン情報を付加する場合の例を考えます。 //test1 パッケージの Test クラス package test1; public class Test { public static void main(String[] argv) { System.out.println("--- package info ---"); Package pkg = Test.class.getPackage(); System.out.println(pkg.getSpecificationTitle()); System.out.println(pkg.getSpecificationVendor()); System.out.println(pkg.getSpecificationVersion()); System.out.println(pkg.getImplementationTitle()); System.out.println(pkg.getImplementationVendor()); System.out.println(pkg.getImplementationVersion()); System.out.println("--------------------"); } } //test2 パッケージの Test クラス package test2; public class Test { public static void main(String[] argv) { System.out.println("--- package info ---"); Package pkg = Test.class.getPackage(); System.out.println(pkg.getSpecificationTitle()); System.out.println(pkg.getSpecificationVendor()); System.out.println(pkg.getSpecificationVersion()); System.out.println(pkg.getImplementationTitle()); System.out.println(pkg.getImplementationVendor()); System.out.println(pkg.getImplementationVersion()); System.out.println("--------------------"); } } 上記をコンパイルして /CLASSROOT/ | +- test1 | | | +- Test.class | +- test2 | +- Test.class のようなパッケージ、クラス階層となっているとします。 この場合は以下の手順でバージョン情報を付加することが できます。 1.マニフェストファイル用エントリの作成 Manifest-version: 1.0 Name: test1/ Implementation-Title: "test1" Implementation-Version: "build01" Implementation-Vendor: "SAMPLE system. Inc." Specification-Title: "version sample 1" Specification-Version: "1.0" Specification-Vendor: "SAMPLE co.ltd." Name: test2/ Implementation-Title: "test2" Implementation-Version: "build02" Implementation-Vendor: "SAMPLE system. Inc." Specification-Title: "version sample 2" Specification-Version: "2.0" Specification-Vendor: "SAMPLE co.ltd." 上記の内容をファイル MFSAMPLE として保存します。 2.JAR ファイルの作成 > jar cvmf MFSAMPLE sample.jar test1 test2 と入力し JAR ファイル(sample.jar)を作成します。 これで、バージョン情報の付いた JAR ファイルが生成されました。 次のコマンドにより、バージョン情報を確認できます。 > java -cp sample.jar test1.Test --- package info --- "version sample 1" "SAMPLE co.ltd." "1.0" "test1" "SAMPLE system. Inc." "build01" -------------------- > java -cp sample.jar test2.Test --- package info --- "version sample 2" "SAMPLE co.ltd." "2.0" "test2" "SAMPLE system. Inc." "build02" -------------------- 参考記事[JavaHouse-Brewers:22498]
[S017 Q-15]
Back
import は C の #include とは違うのですか? [S017 A-15] 違います。 Java での import 宣言は必須ではありません。 例えば //サンプルその1 //import 宣言によって java.util.HashTable をインポートする import java.util.HashTable; public class Test { public void sample() { HashTable hashTable = new HashTable(); .... } } //サンプルその2 //インポートしない public class Test { public void sample() { java.util.HashTable hashTable = new java.util.HashTable(); .... } } これらの2つのサンプルは全く等価です。 import 宣言による利点は、 完全な名称(fully-qualified class name)を用いずに、単一の識別子に よる名称によって異なるパッケージに配置されたクラスを使用することが できる。 ということです。 また、ソース上の import 宣言は、どのパッケージのクラスを使用している かという情報をもあらわします。 したがって、import 宣言によるインポートは、必要最小限のパッケージ、 クラスについてのみ行うようにし、import Package.*; のようなインポート は避けたほうがよいでしょう。 参考記事[JavaHouse-Brewers:24495]

Back
contributor: Osamu Hasegawa
コメントの送り先 Java FAQ BBS l">Java FAQ BBS