パッケージ②
パッケージの宣言
パッケージを作る側に立って、パッケージを構築していきましょう。
パッケージ
まずは、パッケージ宣言(package declation)です。以下の形式で行います。
package パッケージ名;
この宣言は、インポート宣言やクラス宣言よりも前に置かなければなりません。そのため、翻訳単位(translation unit)の構文図は以下のようになります。
この構文図は、パッケージ宣言について以下のことを示しています。
- パッケージ宣言はなくてもよい。
- パッケージ宣言を2個以上置くことはできない。
■無名パッケージ
ソースファイルにパッケージ宣言が無い場合には、そのソースファイル中で定義したクラスは無名パッケージ(unnamed package) に所属します。無名パッケージに所属するクラスの完全限定名は、単純名と一致します。無名パッケージをディレクトリに例えると、ルートディレクトリのようなものになります。
■パッケージ宣言
パッケージ宣言が置かれたソースプログラム中で宣言されたすべてのクラスは、そのパッケージに所属することになります。例として以下のコードを見てみましょう。
package shape;
class Triangle{
//…
}
class Rectangle{
//…
}
この場合は、2つのクラスがパッケージに所属することになります。その結果、各クラスの単純名と完全限定名は以下のようになります。
- 単純名 Triangle 完全限定名 shape.Triangle
- 単純名 Rectangle 完全限定名 shape.Rectangle
互いのクラスを単純名でアクセスすることができます。パッケージとクラスの命名に当たっては注意が必要です。それは、1つのパッケージ中に、同一名のパッケージとクラスが存在することが許されないです。
パッケージとディレクトリ
パッケージを作成する場合は、パッケージ名と同一名のディレクトリ中にソースファイルとクラスファイルを置くのが基本的な構成です。その例がを示したのが以下の図です。
パッケージ名が a なので、a という名前のディレクトリを作成して、その中にソースファイル A1.java を格納します。クラス a.A1 を利用しているのが、以下の2つです。
- X.java…クラス A1 を完全限定名 a.A1 として利用します。
- Y.java…a.A1 をインポートする宣言した上でクラス A1 を単純名で利用します。
実際にパッケージを作ってみましょう。クラスRandId をパッケージ id に所属させましょう。
//RandId.java
//識別番号クラス
package id;
import java.util.Random;
public class RandId {
private static int counter;
private int id;
static{
Random rand = new Random();
counter = rand.nextInt(10) * 100;
}
//コンストラクタ
public RandId(){
id = ++counter;
}
//識別番号取得
public int getId(){
return id;
}
}
- パッケージの宣言です。import 宣言よりも前に置かなければなりません。このソースプログラム内で定義されるクラス RandId は、パッケージ id に所属します。
- クラス RandId の宣言です。単純名は RandId で、完全限定名は、id.Randidになります。
このクラスを利用するプログラムを以下に示します。package宣言がないので、クラス RandIdTester は無名パッケージに所属します。
//RandIdTester.java
//識別番号クラスRandIdの利用例
import id.RandId;
public class RandIdTester {
public static void main(String[] args){
RandId a = new RandId();
RandId b = new RandId();
RandId c = new RandId();
System.out.println("aの識別番号:" + a.getId());
System.out.println("bの識別番号:" + b.getId());
System.out.println("cの識別番号:" + c.getId());
}
}
2つのプログラムのディレクトリ構成の例を示したのが、次の図になります。
一意なパッケージ名
自作したクラス群をパッケージ化して広く公開する際には、誰もが使いそうなパッケージ名を与えるわけにはいきません。パッケージには一意な名前を与える必要があります。そのために推奨されているのが、インターネットのアドレスを逆順に並べるという方法です。
クラスとメンバのアクセス性
パッケージによるカプセル化について言及していきます。
クラスのアクセス制御
- public クラス
- 非 public クラス
■public クラス
キーワード public付きで宣言されたクラスになります。パッケージとは無関係に利用できます。クラスのアクセス性は、公開アクセス(public access)となります。
■非 public クラス
キーワード publicを付けずに宣言されたクラスです。そのクラスが所属するパッケージ内からは利用できますが、他のパッケージからは利用できません。クラスのアクセス性は、パッケージアクセス(package access)になります。なお、パッケージアクセスは、デフォルトアクセス(default access)と呼ばれます。
メンバのアクセス制御
メンバのアクセス性には、以下の4種類があります。
- 公開(public)アクセス
- 限定公開(protected)アクセス
- パッケージ(default)アクセス
- 非公開(private)アクセス
上の4つの規則を簡単にまとめたのが以下の表になります。
キーワード/クラス | publicクラス | 非 publicクラス |
public | 公開アクセス | パッケージアクセス |
protected | 限定公開アクセス | × |
(なし) | パッケージアクセス | × |
private | 非公開アクセス | × |
これらのアクセス性を図を見ながら理解を深めましょう。
■公開(public)アクセス…メソッド m1
パッケージの中からも外からも利用できます。同一パッケージに所属するクラスPからも、異なるパッケージに所属するクラスQからも、メソッドm1を呼び出せます。
■限定公開(protected)アクセス…メソッド m2
パッケージの中からのみ利用できます。そのため、異なるパッケージに所属するクラスQからメソッドm2を呼び出すことはできません。
■パッケージ(default)アクセス…メソッド m3
同じパッケージ中からのみ利用できます。そのため、異なるパッケージに所属するクラスQからメソッドm3を呼び出すことはできません。
■非公開(private)アクセス…メソッド m4
クラス内部でのみ利用できます。そのため、同じパッケージに所属するクラスPからのメソッドm4を呼び出すことはできません。