Javaのパッケージ(package)は「関連するクラスやインターフェースをグループ化してまとめたもの」です。
Javaのプログラムが大規模になると、たくさんのクラスやインターフェースが必要になってきます。これらを整理せずに置いておくと、コードがごちゃごちゃしてきて管理が非常に難しくなります(あのクラスはどこにあったっけ・・・?的な)。そこでJavaでは「package:パッケージ」という仕組み使って、関連するクラスやインターフェースをまとめて整理し、必要に応じてパッケージを後からインポートしそれを利用します。
パッケージには、1:標準で提供されるもの、2:他の人から提供されるもの、3:独自に作成するものなど、いくつかの種類があります。
このページでは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); } }
このように、パッケージは名前空間を提供し、同じ名前のクラスが異なるパッケージに存在することを可能にする、というのがパッケージの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
は、ClassA
のpublic
、protected
、およびデフォルト(パッケージプライベート)フィールドにアクセスできますが、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
は、ClassA
のpublic
フィールドにアクセスできます。同様に、ClassC
はClassA
のサブクラスであるため、protected
フィールドにもアクセスできますが、default
およびprivate
フィールドにはアクセスできません。
パッケージはプログラムを1つにまとめるだけでなく、名前空間の提供とアクセス制御も同時に行っている!ものだとおさえておきましょう。
で、このパッケージは自分で作るものもあれば、誰かから提供されるものもあります。続いてはパッケージの種類についてご説明します。
パッケージの種類
Javaのパッケージは大きく分けて以下4つに分類されます。ザックリいえば、①誰かが作ってくれたもの か ②自分で作ったもの の2種類ということになるのですが、ここでは正式に以下4分類をご紹介します。
1. 標準パッケージ(Standard Packages)
標準パッケージは、Java開発キット(JDK)に含まれており、基本的な機能やAPIを提供するもの。これらのパッケージはJavaプログラムの基盤を構成し、多くの一般的な操作に使用されます。
ポイント 標準パッケージの具体例
- java.lang
- Javaの基本的なクラスをまとめたもの。例:
String
,Math
,Integer
など。
- Javaの基本的なクラスをまとめたもの。例:
- java.util
- コレクションフレームワークやユーティリティクラスをまとめたもの。例:
ArrayList
,HashMap
,Date
など。
- コレクションフレームワークやユーティリティクラスをまとめたもの。例:
- java.io: 入出力操作に関するクラスをまとめたもの。例:
File
,InputStream
,OutputStream
など。
2. 拡張パッケージ(Extension Packages)
拡張パッケージは、標準ライブラリには含まれないが、Javaプラットフォームによって公式に提供される追加の機能を含むパッケージ。javax
で始まることが多く、特定の用途に対応したクラスやインターフェースをまとめたものです。
ポイント 拡張パッケージの具体例
- javax.servlet
- サーブレットAPIを提供し、Webアプリケーションの開発に使用される。例:
HttpServlet
,ServletRequest
,ServletResponse
など。
- サーブレットAPIを提供し、Webアプリケーションの開発に使用される。例:
- javax.swing
- GUI(グラフィカルユーザインタフェース)コンポーネントを提供。例:
JFrame
,JButton
,JLabel
など。
- GUI(グラフィカルユーザインタフェース)コンポーネントを提供。例:
- javax.xml
- XML処理に関するクラスを提供。例:
DocumentBuilder
,XPath
,Transformer
など。
- XML処理に関するクラスを提供。例:
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!
まとめると、カスタムパッケージを作成する手順は以下の通り。
- クラスファイルの最初にパッケージを宣言する。
- パッケージ名に対応するディレクトリ構造を作成する。
- カスタムパッケージのクラスを作成し、他のクラスからインポートして使用する。
- プロジェクトをコンパイルし、実行する。
パッケージの使い方/インポート方法
最後にパッケージの使い方についてご説明しておきます。
パッケージは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); } }
Tips:名前の衝突を避ける方法
異なるパッケージに同じ名前のクラスが存在する場合、名前の衝突が発生することがあります。このような場合には、クラスの完全修飾名(パッケージ名を含むクラス名)を使用することで、名前の衝突を避けることができます。
以下の例では、java.util.Date
とjava.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); } }