パッケージ(package)について学ぶ java超初心者の勉強

2020-11-22

パッケージ間のアクセス制御に慣れたいなと思い勉強し直すことにしました。

パッケージ(package)とは

パッケージ(package)とはJavaのクラスを分類するための仕組みです。
グループ化というとわかりやすいかもしれません。クラスに名前空間を提供したりアクセス制御としても使われます。

クラスを探しやすくなる便利な機能です。
また、例えばprintというクラスがあったとして、パッケージが分かれていないと同じ名前を使用することはできません。
大規模になれば何人かで作業することもありますが、パッケージを分けて作業すれば同じ名前のクラスを作成しても問題が起きないという利点もあります。

パッケージの宣言

ファイルには自分の属するパッケージ名を宣言します。

package パッケージ名;

パッケージ名は大文字にも対応していますが小文字で作成するのが一般的だそうです。

階層が深くなった場合はドットで区切ります。

package パッケージ名.サブパッケージ名;

階層が一つ下がったパッケージをサブクラスと言います。
階層が深くなった分だけドットでつないで書くことができます。

ちなみに大規模なシステムを開発する場合、パッケージ名が同じ場合が発生してしまうことがあります。
パッケージ名が重複することを避けるため、ある一意の値を元にパッケージ名を作成する習慣があります。
その一意の値はドメインです。ドメインはネット上の住所の役割を担っているため1つしかありません。

本サイトのドメインの場合は「https://programmer-life.work/」なので以下のようにパッケージが作成されます。

work.programmer-life

逆さに書くのが通例です。

importの宣言

他のパッケージのクラスを使用する時にインポートを宣言します。
その際の書き方は以下のようになります。

import パッケージ名.サブパッケージ名.クラス名;

import java.util.*;なんてのはよく見かけると思います。

※「*」はオンデマンドインポートで上記の場合java.utilパッケージに含まれている全てのクラスとインターフェイスをimportします。
オンデマンドインポートは名前の衝突を引き起こす可能性があるため単一型インポートが基本です。

宣言の順番

パッケージの宣言は必ず先頭に書きます。
書く順番としてはとしては「package」→「import」→「class」となります。

package work.programmer-life;
import java.util.*;
public class test{ }

パッケージの種類

パッケージには2つ種類があります。
名前のあるパッケージ名前のないパッケージです。
名前のないパッケージのことをデフォルトパッケージと言い(無名パッケージとも言う)、名前がない場合はデフォルトパッケージに属します。
(パッケージを宣言していない場合は、デフォルトパッケージとなります。)
デフォルトパッケージは練習などの簡単なプログラミングに使われ、規模の大きなプログラムに使用されることはまずないそうです。

パッケージのアクセス

ここではアクセス修飾子の深堀はせずパッケージ間のアクセス制御について学びます。

アクセス制御については以下でまとめています。

パッケージ間のアクセスについてこちらではデフォルトかそうでないかで分けて説明していきます。
名前のついたパッケージであれば、import宣言をすることでクラスをimportし使用することができます(またはフルパスで明記)。
ではpackage文の記載されていないデフォルトパッケージに属するクラスはどのように呼び出すのでしょうか?

結論から言えば基本的に呼び出すことはできません。
(無理やりリフレクションAPIで呼び出すことができますが、使い方注意)

サンプルコードを用意したので興味のある方は実験してみると動きがわかって楽しいかと思います。

サンプルコード デフォルトパッケージはデフォルトパッケージにしかアクセスできない

デフォルトパッケージに属するクラスへは同じデフォルトパッケージに属するクラスしか呼び出せません。

public class A{
    public static void test(){
        System.out.println("default package");
    }
}

public class B{
    public static void main(String[] arg){
        A.test(); //呼び出せる
    }
}

このことから大規模なシステムへは不向きと言われています。

サンプルコード デフォルトパッケージと名前のあるパッケージ

work.programmer-lifeパッケージに属しているクラスからデフォルトパッケージに属するクラスは呼び出せなません。

public class A{
    public static void test(){
        System.out.println("default package");
    }
}

package work.programmer-life;
public class B{
    public static void main(String[] arg){
        A.test(); //コンパイルエラー
    }
}

サンプルコード 名前のあるパッケージ

同じパッケージに属するクラスへはアクセス可能です。パッケージ名が異なってもimportすれば使用できます。

package work.programmer-life;
public class A{
    public static void test(){
        System.out.println("work.programmer-life package");
    }
}

package other;
public class A2{
    public static void test(){
        System.out.println("other package");
    }
}

package work.programmer-life;
import other.A2;
public class B{
    public static void main(String[] arg){
        A.test(); //呼び出せる
        A2.test();//呼び出せる
    }
}

名前が重複した場合

パッケージが異なってもクラス名が同じだとインポートしたクラスが優先され同一パッケージのクラスを呼び出せなくなるので注意しましょう。その場合はフルパスを書くことで回避できます。

package work.programmer-life;
public class A{
    public static void test(){
        System.out.println("work.programmer-life package");
    }
}

package other;
public class A{
    public static void test(){
        System.out.println("other package");
    }
}

package work.programmer-life;
public class B{
    public static void main(String[] arg){
        A.test(); //呼び出せる
        other.A.test();//呼び出せる
    }
}

おわり

クラスやメソッドのアクセス制御でpublic、protected、privateなどと覚えたので、パッケージにもpublicなどあると勘違いしていました。
デフォルトパッケージもリフレクションAPIというのを使うとアクセスできるらしいですが、イレギュラーらしいので初心者の身としては使うことはなさそうなので特に深ぼりしませんでした。

 参考 

https://www.geeksforgeeks.org/packages-in-java/
What's the syntax to import a class in a default package in Java? [duplicate]

Java

Posted by Nakamoto