カテゴリー
Java

Java(Step9-2)

パッケージ②

パッケージの宣言

パッケージを作る側に立って、パッケージを構築していきましょう。

パッケージ

まずは、パッケージ宣言(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;
    }
}
  1. パッケージの宣言です。import 宣言よりも前に置かなければなりません。このソースプログラム内で定義されるクラス RandId は、パッケージ id に所属します。
  2. クラス 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());
    }
}
RandIdTester.java実行結果

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を呼び出すことはできません。