PR

Java:パッケージ(package)の基本を3分で整理

Java

Javaのパッケージ(package)は簡単に言うと「関連するクラスインターフェースをグループ化してまとめたもの」です。

Javaのプログラムが大規模になると、多くのクラスやインターフェースが必要になります。これらを整理せずに置いておくとコードがごちゃごちゃしてきて、管理が難しくなります(あのクラスはどこにあったっけ・・・?的な)。そこでJavaでは「パッケージ」を使って、関連するクラスやインターフェースをまとめて整理し、必要に応じてパッケージを後からインポートしそれを利用するということ。

また、パッケージは、標準で提供されるもの、追加で提供されるもの、独自に作成するものなど、いくつかの種類があります。

このページではJavaにおけるパッケージとは何か?実際の使い方や作り方までを網羅的にわかりやすくご説明します。

関連 Javaの1stステップ:基本的な構文ルールを1分で復習!

スポンサーリンク

Javaのパッケージとは?わかりやすく

パッケージ(package)とは、クラスやインターフェースを1つにまとめて整理したもの。が、単にまとめるだけではありません。

ここではパッケージの基本的な仕組み(利点)を簡単にご説明しておきます。

参考 クラスとは? / インターフェースとは?

パッケージの役割1:クラスやインターフェースの整理

Javaのプログラムが大規模になると、多くのクラスやインターフェースが生成されるようになります。パッケージはこれらを論理的なグループとしてまとめ、管理しやすくするために用いられます。

例えば、java.utilというパッケージには、コレクションフレームワークやユーティリティクラスが含まれています。同じ目的のクラスを1つのグループにまとめるために使われる、というのがパッケージの第1の役割です。

参考 コレクションフレームワークとは?

パッケージの役割2:名前空間の提供

第2の役割は名前空間を提供するということ。名前空間というと難しく聞こえますが、要するに同じ名前のクラスを異なるパッケージに同時に存在させることを可能にするということ。

例えば、Javaには日付を扱うためのクラスが2つあります。1つはjava.utilパッケージに属するDateクラス、もう1つはjava.sqlパッケージに属するDateクラス。これらは同じ名前のクラスですが、異なるパッケージに属しているため、1つのプログラムに同居することが可能です。

  • java.util.Date: 一般的な日付と時間を扱うためのクラス。
  • java.sql.Date: データベースの日時型を扱うためのクラス。
import java.util.Date;  // 一般的な日付を扱うクラスをインポート
import java.sql.Date;   // データベースの日時型を扱うクラスをインポート

public class DateExample {
    public static void main(String[] args) {
        // java.util.Dateを使って現在の日付と時間を取得
        Date utilDate = new Date();
        System.out.println("java.util.Date: " + utilDate);

        // java.sql.Dateを使って特定の日付を設定
        Date sqlDate = new Date(System.currentTimeMillis());
        System.out.println("java.sql.Date: " + sqlDate);
    }
}

参考 クラスの基本(書き方・利用方法)を3分で

このように、パッケージは名前空間を提供し、同じ名前のクラスが異なるパッケージに存在することを可能にする、というのがパッケージの2つ目の役割。

パッケージの役割3:アクセス制御

第3の役割はアクセス制御です。Javaのパッケージはアクセス修飾子と組み合わせることで、アクセス制御をより細かく管理するために使われます。

参考 アクセス修飾子とは?

パッケージ自体が特定のアクセス修飾子を持つわけではありませんが、アクセス修飾子とパッケージを組み合わせることで、クラスやメンバー(フィールドやメソッド)のアクセス範囲を決定します。

アクセス修飾子同一クラス同一パッケージ内の他のクラスサブクラス(同一パッケージ)サブクラス(異なるパッケージ)他のパッケージのクラス
public
protected〇(※1)
デフォルト
private

※1: protectedメンバーは、異なるパッケージのサブクラスからアクセスする場合、サブクラス内でthisを使ってアクセスする必要がある。

サンプルコード アクセス修飾子とパッケージの関係の簡易サンプル

1:パッケージAのクラス

// パッケージAのクラス
package com.example.packageA;

public class ClassA {
    public String publicField = "Public Field";
    protected String protectedField = "Protected Field";
    String defaultField = "Default Field";  // デフォルトアクセス(パッケージプライベート)
    private String privateField = "Private Field";

    public void showFields() {
        System.out.println("publicField: " + publicField);
        System.out.println("protectedField: " + protectedField);
        System.out.println("defaultField: " + defaultField);
        System.out.println("privateField: " + privateField);
    }
}

2:同じパッケージ内のクラス

// パッケージAの別のクラス
package com.example.packageA;

public class ClassB {
    public void accessFields() {
        ClassA obj = new ClassA();
        System.out.println(obj.publicField);     // アクセス可能
        System.out.println(obj.protectedField);  // アクセス可能
        System.out.println(obj.defaultField);    // アクセス可能
        // System.out.println(obj.privateField); // アクセス不可(コンパイルエラー)
    }
}

ClassBは、ClassApublicprotected、およびデフォルト(パッケージプライベート)フィールドにアクセスできますが、privateフィールドにはアクセスできません。

3:異なるパッケージのクラス

// パッケージBのクラス
package com.example.packageB;

import com.example.packageA.ClassA;

public class ClassC extends ClassA {
    public void accessFields() {
        ClassA obj = new ClassA();
        System.out.println(obj.publicField);     // アクセス可能
        // System.out.println(obj.protectedField);  // アクセス不可(インスタンス経由の場合)
        // System.out.println(obj.defaultField);    // アクセス不可
        // System.out.println(obj.privateField);    // アクセス不可

        System.out.println(this.protectedField); // アクセス可能(サブクラス経由の場合)
    }
}

ClassCは、ClassApublicフィールドにアクセスできます。同様に、ClassCClassAのサブクラスであるため、protectedフィールドにもアクセスできますが、defaultおよびprivateフィールドにはアクセスできません。

パッケージはプログラムを1つにまとめるだけでなく、名前空間の提供とアクセス制御も同時に行っている!ものだとおさえておきましょう。

で、このパッケージは自分で作るものもあれば、誰かから提供されるものもあります。続いてはパッケージの種類についてご説明します。

パッケージの種類

Javaのパッケージは大きく分けて以下4つに分類されます。ザックリいえば、①誰かが作ってくれたもの②自分で作ったもの の2種類ということになるのですが、ここでは正式に以下4分類をご紹介します。

1. 標準パッケージ(Standard Packages)

標準パッケージは、Java開発キット(JDK)に含まれており、基本的な機能やAPIを提供するもの。これらのパッケージはJavaプログラムの基盤を構成し、多くの一般的な操作に使用されます。

ポイント 標準パッケージの具体例

  1. java.lang
    • Javaの基本的なクラスをまとめたもの。例: String, Math, Integerなど。
  2. java.util
    • コレクションフレームワークやユーティリティクラスをまとめたもの。例: ArrayList, HashMap, Dateなど。
  3. java.io: 入出力操作に関するクラスをまとめたもの。例: File, InputStream, OutputStreamなど。

2. 拡張パッケージ(Extension Packages)

拡張パッケージは、標準ライブラリには含まれないが、Javaプラットフォームによって公式に提供される追加の機能を含むパッケージjavaxで始まることが多く、特定の用途に対応したクラスやインターフェースをまとめたものです。

ポイント 拡張パッケージの具体例

  1. javax.servlet
    • サーブレットAPIを提供し、Webアプリケーションの開発に使用される。例: HttpServlet, ServletRequest, ServletResponseなど。
  2. javax.swing
  3. javax.xml
    • XML処理に関するクラスを提供。例: DocumentBuilder, XPath, Transformerなど。

3. カスタムパッケージ(Custom Packages)

カスタムパッケージは、開発者が独自に作成するパッケージです。プロジェクト固有のクラスやインターフェースを整理し、再利用性を高めるために使用されます。

詳しくは後述しますが、以下のようにクラスファイルの最初の個所でpackageキーワードを用いて宣言します。

package com.example.myapp;

public class MyClass {
    // クラスの内容
}

4. サードパーティパッケージ(Third-Party Packages)

サードパーティパッケージは、外部のライブラリやフレームワークに含まれるパッケージです。これらのパッケージは、特定の機能や拡張機能を提供し、Javaエコシステムの一部として広く利用されています。

以下のようなcom.google.gson: JSON処理のためのGsonライブラリなどが一例です。

import com.google.gson.Gson;

public class JsonExample {
    public static void main(String[] args) {
        Gson gson = new Gson();
        String json = gson.toJson(new Person("John", 30));
        System.out.println(json);
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

で、ここからはカスタムパッケージの作り方と、パッケージの使い方についてご説明します。

カスタムパッケージの作り方

ここからは、カスタムパッケージを作成する手順を順を追って1つ1つ説明していきます。

ステップ1:パッケージの宣言

カスタムパッケージを作成するには、クラスファイルの最初にpackageキーワードを利用してパッケージを宣言します。パッケージ名は通常、逆ドメイン名形式を使用して一意にします。例えば、com.example.myappというパッケージを作成する場合、以下のように宣言します。

package com.example.myapp;

public class MyClass {
    public void sayHello() {
        System.out.println("Hello from MyClass in com.example.myapp package!");
    }
}

ステップ2:ディレクトリ構造の作成

次に、パッケージ名に対応するディレクトリ構造をプロジェクト内に作成します。パッケージcom.example.myappに対応するディレクトリ構造は以下の通り。

project_root/
└── src/
    └── com/
        └── example/
            └── myapp/
                └── MyClass.java

ステップ3:実際のコードを作成する

次に、カスタムパッケージを使うクラスを作成し、これらのクラスを他のクラスからインポートして使用します。インポートを行う場合はimportキーワードを利用します。

importキーワードの使い方は後ほど再度詳しくご説明します。

サンプルコード カスタムパッケージのクラス

// ファイル: src/com/example/myapp/MyClass.java
package com.example.myapp;

public class MyClass {
    public void sayHello() {
        System.out.println("Hello from MyClass in com.example.myapp package!");
    }
}

サンプルコード カスタムパッケージを使用するクラス

// ファイル: src/com/example/anotherpackage/Main.java
package com.example.anotherpackage;

import com.example.myapp.MyClass;

public class Main {
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.sayHello();
    }
}

ステップ4:パッケージをコンパイルして実行

最後にカスタムパッケージを含むプロジェクトをコンパイルします。プロジェクトのルートディレクトリで以下のコマンドを実行して、すべてのJavaファイルをコンパイルします。

javac -d bin src/com/example/myapp/MyClass.java src/com/example/anotherpackage/Main.java

-d binオプションは、コンパイルされたクラスファイルをbinディレクトリに出力することを指定しています。

次に、コンパイルされたクラスを実行します。

java -cp bin com.example.anotherpackage.Main

このコマンドは、クラスパス(-cp bin)を指定して、Mainクラスを実行します。出力は以下のようになります。

Hello from MyClass in com.example.myapp package!

まとめると、カスタムパッケージを作成する手順は以下の通り。

  1. クラスファイルの最初にパッケージを宣言する。
  2. パッケージ名に対応するディレクトリ構造を作成する。
  3. カスタムパッケージのクラスを作成し、他のクラスからインポートして使用する。
  4. プロジェクトをコンパイルし、実行する。

パッケージの使い方/インポート方法

最後にパッケージの使い方についてご説明しておきます。

パッケージはimport文でインポートすることで簡単に利用できるようになります。

import文の使い方

他のパッケージのクラスを使用するためには、import文を使ってクラスをインポートします。import文は、パッケージ名とクラス名を指定します。

以下は、java.utilパッケージのArrayListクラスをインポートして利用する方法です。

import java.util.ArrayList;

public class ImportExample {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Hello");
        list.add("World");
        System.out.println(list);
    }
}

参考 ArrayListの使い方

Tips:名前の衝突を避ける方法

異なるパッケージに同じ名前のクラスが存在する場合、名前の衝突が発生することがあります。このような場合には、クラスの完全修飾名(パッケージ名を含むクラス名)を使用することで、名前の衝突を避けることができます。

以下の例では、java.util.Datejava.sql.Dateの両方を使用していますが、名前の衝突を避けるために、完全修飾名を使用しています。

import java.util.Date;

public class DateExample {
    public static void main(String[] args) {
        // java.util.Dateを使用
        Date utilDate = new Date();
        System.out.println("java.util.Date: " + utilDate);

        // java.sql.Dateを使用
        java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis());
        System.out.println("java.sql.Date: " + sqlDate);
    }
}

Tips:ワイルドカード(*)を使ったインポート

パッケージ内の複数のクラスをインポートする場合、ワイルドカード(*)を使用することで、パッケージ内のすべてのクラスを一度にインポートすることが可能です。

必要なクラスだけを個別にインポートする方が、コードの可読性が向上しますが、一応Tipsとしてご紹介。

以下は、java.utilパッケージ内のすべてのクラスをインポートする例です。

import java.util.*;

public class WildcardImportExample {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Hello");
        list.add("World");
        System.out.println(list);

        HashMap<Integer, String> map = new HashMap<>();
        map.put(1, "One");
        map.put(2, "Two");
        System.out.println(map);
    }
}

このWebサイトは現役のエンジニアが以下3点を目的として運営しています。

  1. 勉強:一度理解した内容を忘れないように。
    → アウトプットは「最強のインプット」である! 
  2. 備忘:忘れたとしても後から見返せるように。
    → 未来の自分への「お手紙」を書いています。 
  3. 共有:〇〇ってこうだったんだ!の感動をシェアできるように。
    → あなたの知識は誰かにとっての「価値ある情報」です。 

副業ブログの始め方はこちらから

スポンサーリンク
Java
シェアする
ビズドットオンラインをフォローする
タイトルとURLをコピーしました