パッケージとは、クラスが属する入れ物です。
例えばScannerクラスは、java.utilのパッケージに入っています。
そして、Scannerクラスの変数stdinを宣言する場合は、java.util.Scanner stdin;
と宣言できます。
public class Test{
public static void main(String []arg){
java.util.Scanner stdin = new java.util.Scanner(System.in);
・・・以下省略・・・
または、ファイル先頭にimport java.util.Scannerを書くことにより、
パッケージを省略したクラス名だけで変数宣言ができるようになります。
import java.util.Scanner;
public class Test{
public static void main(String []arg){
Scanner stdin = new Scanner(System.in);
// ↑
//importしているのでjava.utilを省略している。
・・・以下省略・・・
上記のimport java.util.Scanner;は、import java.util.*;と書いても動作します。
この*は、任意のクラスと言う意味で、java.utilのパッケージ内に
ある全てのクラス名を使えるようにする指定です。
別のクラスの例で示します。
FileInputStreamクラスは、java.ioのパッケージに入っています。
そして、FileInputStreamクラスの変数fisを宣言する場合は、
java.io.FileInputStream fis;と宣言できます。
または、ファイル先頭にimport java.io.FileInputStreamを書くことにより、
パッケージを省略したクラス名だけで変数宣言ができるようになります。
なお、実行する場合にはこれらパッケージに属するクラスが必要です。
それは、コマンドラインで実行する場合に、環境変数のclasspathで指定されます。
java の実行時に、classpathを指定するオプションが使えて、その例を以下に示します。
D:\Java>java -classpath .;C:\jdk1.6.0_06 Test
この例ではjava.io.FileInputStreamを利用する場合、.\java\io
にあるFileInputStreamクラスで実行するか?
または、C:\jdk1.6.0_06\java\ioにあるFileInputStreamクラスで実行することになります。
JDK(Java Development Kit)のクラスが利用される場合、このディレクトリ内に次のsrc.zipがあって、
その中にjavaのフォルダがって、
その中のioのフォルダがあって、
その中にFileInputStream.javaのファイルがあり、そのクラスが使われて
実行します。
クラスのソースファイル先頭に package パッケージ名; を
書くことで、そのクラスは、パッケージ名のパッケージに属する指示となります。
そして、そのパッケージ名のディレクトリの中に入れる必要があります。
(パッケージは、実質的にその名前のディレクトリになっています。)
ここで、実際にRecord2をrecのパッケージにする例で示します。
カレントディレクトリ>javac Test.java のように、
これまでコンパイルや実行の基準とするディレクトリが一つのルートになるので、
この中にrecの名前のフォルダを作成します。
そして、recの中に
Record2.java
を移動します。
(カレントディレクトリは、環境変数のclasspath指定で、.で表現される位置です)
そしてRecord2.javaの先頭行に package rec; と書きます。
これで、パッケージ化は終わりです。
次にこれを利用するTestクラスですが、Test.javaの先頭に、import rec.Record2; を書きます。以下に簡単なTest.javaのソースを示します。
import rec.Record2; public class Test { public static void main(String[] arg) { Record2 rec = new Record2("A01", 4);//コンストラクタ rec.display(1);//表示 } }
カレントディレクトリ>javac Test.java
の実行で、Test.javaをコンパイルすると、
recの中に、Record2.classファイルが生成されるのが確認できるでしょう。
また、直接にRecord2.javaをコンパイルする場合は次のように実行します。
カレントディレクトリ>javac rec\Record2.java
(カレントディレクトリ\rec>javac Record2.java では正しくコンパイルできないことに注意ください)
これによって得られるクラスのクラス図は次のように書きます。
(パッケージ化する前のRecord2.javaが、前ページまでに追加したメソッドを持っている場合です。)
rec:: がパッケージを意味します。
(クラス図では、必項でなく必要に応じて書きます)
なお、java で、パッケージを指定したクラスのmainを実行する場合、
パッケージ名.クラス名 と指定します。
次の例のように実行させるのですが、このRecord2にはmainが無いのでエラーとなります。
カレントディレクトリ>java rec.Record2 Exception in thread "main" java.lang.NoSuchMethodError: main カレントディレクトリ>
なお、過去のRecord2を利用するソースファイルも、
カレントディレクトリにパッケージ化する前のRecord2.classが残っていれば、コンパイルや実行が可能です。
それはrec内のRecord2ではなく、カレントディレクトリのRecord2.classで動いていることになります。
そしてimport rec.Record2; が指定されるクラスだけが、
rec内のRecord2で動作していることになります。
さて、カレントディレクトリにパッケージ前のRecord2.classが残っていて、
rec内の中にパッケージ化したRecord2.classがある時、
次のファイルをコンパイルするとどうなるでしょうか?
import rec.*;
public class Test {
public static void main(String[] arg) {
Record2 rec = new Record2("A01", 4);//コンストラクタ
rec.display(1);//表示
}
}
このRecord2("A01", 4)は、カレントディレクトリのRecord2.classが使われます。
つまりrec.*の指定では、カレントと、パッケージの両方にクラスがある場合、
カレントの方が優先されます。はっきりとパッケージの中のRecord2を使いたい場合は、
りimport rec.Record2;の指定が必要というわけです。
次、カレントディレクトリにパッケージ前のRecord2.classが無くて、
rec内の中にパッケージ化したRecord2.classがある時、
次のimport指定がないファイルをコンパイルするとどうなるでしょうか?
public class Test {
public static void main(String[] arg) {
Record2 rec = new Record2("A01", 4);//コンストラクタ
rec.display(1);//表示
}
}
それは、次のようなエラーになります。
カレントディレクトリ>javac Test.java
Test.java:3: シンボルを見つけられません。
シンボル: クラス Record2
場所 : Test の クラス
Record2 rec = new Record2("A01", 4);//コンストラクタ
^
では、rec内の中のパッケージ化したRecord2.classのファイルをカレントカレントディレクトリに移動して
コンパイルすると、どうなるでしょうか?結果を以下に示します。
カレントディレクトリ>javac Test.java
Test.java:3: Record2 にアクセスできません。
クラスファイル .\Record2.class は不正です。
クラスファイル rec.Record2 に不正なクラスがあります。
削除するか、クラスパスの正しいサブディレクトリにあるかを確認してください。
Record2 rec = new Record2("A01", 4);//コンストラクタ
^
つまり、パッケージしたクラスファイルには、パッケージの情報が入っており、パッケージと合う正しいディレクトリ
配置しなけば使えないということです。