本ページはプロモーションが含まれています

Java入門

Javaクラスパス完全ガイド!確認方法と設定方法

トム

・都内自社開発企業勤務/Javaバックエンドエンジニア
/Java歴10年以上 ・首都圏在住30代
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎 詳細なプロフィール

Javaを学び始めた頃、誰もが一度はつまづくのが「クラスパス」です。私自身、ClassNotFoundExceptionという赤いエラー文字を見るたびに、頭を抱えていた時期がありました。

10年以上のJava開発経験を振り返り、あの頃の自分が知りたかった「クラスパスのすべて」を体系的にまとめました。

この記事は以下の疑問を持つJava初学者や、設定に自信がない中級者の方に向けています。

  • 「クラスパスって一体何?」
  • 「どうやって設定すればいいの?」
  • 「よく見るあのエラーの意味が分からない」

Javaのクラスパスとは?

クラスパス(Classpath)とは、Javaのプログラム実行時に、必要なクラスファイル(.class)やライブラリ(.jar)を探すための道しるべ です。

Javaはソースコード(.java)をクラスファイル(.class)に変換します。実行時には、Java仮想マシン(JVM)が、これらのクラスファイルをメモリに読み込む必要があります。

その際、JVMは「どのディレクトリやJarファイルを探せば、目的のクラスが見つかるのか」を知らなくてはなりません。この「探す場所のリスト」こそが、クラスパスです。

Java実行時にクラスパスが参照される流れ

JVMはクラスパスに指定された場所だけを、決められた順序で探索します。

  1. ブートストラップクラスパス: Javaの基本ライブラリ(Java 8以前のrt.jarなど、Java実行環境の根幹をなすクラス群)が対象。通常、開発者が意識して設定する場所ではない
  2. 拡張クラスパス: Javaの拡張機能が置かれる場所。(Java 9 でモジュールシステムが登場し、この仕組みは廃止)
  3. ユーザー定義クラスパス: 開発者が作成したクラスや、外部から持ってきたライブラリ(Jarファイル)を指定する場所。私たちが「クラスパスを設定する」と言う場合、通常はここを指す

JVMは、まずブートストラップ、次に拡張クラスパス(Java 8以前)、最後にユーザー定義クラスパスの順でクラスを探します。目的のクラスが最初に見つかった時点で探索は終了し、そのクラスが使用されます。Java 9以降はモジュールシステムの導入により、拡張クラスパスの仕組みは廃止されています。

クラスローダーとクラスパスの関係

実際にクラスパスをたどってクラスファイルを読み込む役割を担っているのが「クラスローダー(Class Loader)」です。

クラスローダーには階層構造(親子関係)があります。

  • ブートストラップクラスローダー: 最上位に位置し、Javaの基本的なクラスを読み込む。
  • 拡張クラスローダー: 拡張ライブラリを読み込む。
  • アプリケーションクラスローダー(システムクラスローダー): ユーザー定義クラスパス(私たちが設定する -cp や環境変数 CLASSPATH)からクラスを読み込む。

Javaは「委譲モデル」を採用しています。クラスの読み込み要求があると、まず親のクラスローダーに処理を依頼します。親が見つけられなければ、自身がクラスパスを探索して読み込みを試みる仕組みです。

CLASSPATH環境変数の基本

クラスパスを設定する最も古い方法の一つに、OSの「環境変数 CLASSPATH」を利用する方法があります。

Windowsの「システムのプロパティ」や、Linux/Macの .bashrc などで CLASSPATH という名前の環境変数を設定すると、java コマンド実行時にその設定が自動で読み込まれます。

設定例(Windows): C:\MyLib\library1.jar;C:\MyProject\classes

設定例(Linux/Mac): /home/user/lib/library1.jar:/home/user/project/classes

ただし、この方法はPC全体(あるいはユーザー全体)に影響を与えてしまいます。プロジェクトごとにバージョンが異なる場合の管理が困難なため、現在は推奨されません。後述するコマンドラインでの指定や、IDE、ビルドツールの利用が一般的です。

Javaのクラスパスを確認する方法

クラスパスを設定したあとは、正しく設定されているか確認しましょう。原因不明のエラーに直面したとき、まず「現在のクラスパスが何になっているか」を確認するだけで、問題の糸口が見つかることも多いです。

環境変数CLASSPATHの確認(コマンドライン)

OS上に設定した CLASSPATH 環境変数の内容は、以下のコマンドで確認できます。

Linux / Mac の場合:

echo $CLASSPATH

Windows(コマンドプロンプト)の場合:

echo %CLASSPATH%

何も表示されなければ、環境変数 CLASSPATH は設定されていません。現在推奨されている -cp オプションを使っている場合は、この出力が空でも問題ありません。

Javaプログラム内からクラスパスを確認する

実行中のプログラムに実際に渡されているクラスパスを確認したい場合は、System.getProperty() を使います。

public class CheckClasspath {
    public static void main(String[] args) {
        String classpath = System.getProperty("java.class.path");
        System.out.println("現在のクラスパス:");
        // 区切り文字で分割して1行ずつ表示
        for (String path : classpath.split(System.getProperty("path.separator"))) {
            System.out.println(" " + path);
        }
    }
}

-verbose:classでクラスのロード状況を確認する

「クラスパスは設定したはずなのに読み込まれない」というときは、-verbose:class オプションが役立ちます。JVMがどのパスからどのクラスをロードしているかをリアルタイムで表示してくれます。

java -verbose:class -cp "./bin:./lib/*" com.example.Main

出力例:
[Loaded com.example.Main from file:/Users/user/project/bin/]
[Loaded com.mysql.cj.jdbc.Driver from file:/Users/user/project/lib/mysql-connector.jar]
…

目的のクラスが期待したパスからロードされているか、あるいはまったく表示されないかで、クラスパスの設定ミスをピンポイントで特定できます。

Javaのクラスパス設定方法【コマンド版】

開発の基本として、コマンドラインでJavaのクラスパスを指定する方法を学びましょう。環境変数 CLASSPATH よりも優先され、プロジェクトごとに設定を完結できます。

javaコマンドでクラスパスを指定する方法(-cp / -classpath)

java コマンド実行時に、-cp または -classpath オプションを使ってクラスパスを指定するのが最も確実な方法です。どちらのオプションも機能はまったく同じです。

基本構文: java -cp [クラスパスの指定] [実行するメインクラス名]

例えば、カレントディレクトリ(.)にある Main.classを実行する場合、それをクラスパスに含める必要があります。

java -cp . Main

※Javaのバージョンや設定によっては . が暗黙的に含まれる場合もありますが、明示的に指定するのが安全です

bin というディレクトリにコンパイル後の .class ファイルが置かれている場合は、以下のようになります。

java -cp bin com.example.Main

com.example.Main のようにパッケージ名を含めた完全修飾名で指定します

複数ディレクトリをクラスパスに設定する方法

複数のディレクトリやJarファイルをクラスパスに含めたい場合は、OS固有の区切り文字で連結します。

OSクラスパスの区切り文字
Windowsセミコロン(;
Linux / Macコロン(:

例えば、./bin ディレクトリと、./lib ディレクトリの両方をクラスパスに設定したい場合、以下のようになります。

Windowsの場合:

java -cp "./bin;./lib" com.example.Main

Linux / Macの場合:

java -cp "./bin:./lib" com.example.Main

※パスに空白が含まれる可能性がある場合は、全体をダブルクォーテーション " で囲むと安全です

Jarファイルをクラスパスに追加する方法

外部ライブラリ(Jarファイル)を利用する場合は、そのJarファイル自体をクラスパスに含めます。

例えば、./bin に自作のクラスがあり、./lib フォルダにある mysql-connector.jar を利用する場合です。

Windowsの場合:

java -cp "./bin;./lib/mysql-connector.jar" com.example.Main

Linux / Macの場合:

java -cp "./bin:./lib/mysql-connector.jar" com.example.Main

また、Java 6以降ではワイルドカード(*)が使えます。特定のディレクトリにあるすべてのJarファイルを一括で指定したい場合に便利です。

例(./lib 内のすべての .jar ファイルを指定):

java -cp "./bin:./lib/*" com.example.Main

注意点: ワイルドカード(*)は、そのディレクトリ直下のJarファイルのみを対象とします。サブディレクトリ内のJarファイルは含まれません。

Javaのクラスパス設定方法【IDE編】

現代のJava開発において、コマンドラインで直接クラスパスを管理することは稀です。IntelliJ IDEAやEclipse、VSCodeといったIDE(統合開発環境)が、クラスパスの管理を大幅に簡素化してくれます。

IntelliJ IDEAでのクラスパス設定手順

IntelliJ IDEAでは、クラスパスは主に依存関係として管理されます。

  1. プロジェクトを右クリックし、「Open Module Settings」(または F4 キー)を選択
  2. 左側のメニューから「Modules」を選び、中央のリストで対象のモジュールを選択
  3. 右側に表示されるタブから「Dependencies」タブを選択
  4. 「+」アイコンをクリックし、「JARs or directories...」を選択して、PC内のJarファイルやクラスファイルがあるディレクトリを指定(Maven/Gradleプロジェクトの場合は、ここにライブラリが自動でリストアップされる)
  5. OK を押して設定を保存

IntelliJでは、GUIで設定した内容が .iml ファイルなどに保存され、実行やデバッグ時に自動でクラスパスが設定されます。

Eclipseでのビルドパス(クラスパス)設定手順

Eclipseでは、クラスパスは「ビルド・パス」と呼ばれます。

  1. プロジェクト・エクスプローラーで対象のプロジェクトを右クリック
  2. 「Build Path」 > 「Configure Build Path...」を選択
  3. 開かれたダイアログで「Libraries」タブを選択
  4. 右側のボタンを使う
    • Add JARs...: プロジェクト内に既にあるJarファイルを追加
    • Add External JARs...: プロジェクト外(PC内の任意の場所)にあるJarファイルを追加
    • Add Library...: JRE System Library など、Eclipseが管理するライブラリを追加
    • Add Class Folder...: クラスファイル(.class)が含まれるフォルダを追加
  5. 追加後、「Apply and Close」で設定を保存

Eclipseでは、この設定は .classpath というファイルに記録されます。

VSCodeでJavaプロジェクトのクラスパスを管理する方法

VSCode (Visual Studio Code) でJava開発を行う場合、「Extension Pack for Java」のインストールが前提となります。

VSCodeでのクラスパス管理は、プロジェクトの種類によって異なります。

Maven/Gradleプロジェクトの場合

pom.xml (Maven) や build.gradle (Gradle) に依存関係を記述します。VSCodeのJava拡張機能がこれらのファイルを認識し、必要なライブラリを自動でダウンロードし、クラスパスを構成します。

非Maven/Gradleプロジェクト(軽量プロジェクト)の場合

VSCodeはクラスパスの設定を .vscode/settings.json ファイルで管理できます。

設定例(.vscode/settings.json)

{ "java.project.referencedLibraries": [ "lib/**/*.jar", "c:/path/to/external/library.jar" ] } 

java.project.referencedLibrariesに、Jarファイルのパスや、ディレクトリ(ワイルドカード使用可)を指定します。

Javaのクラスパスでよく起きるエラーと解決方法

Java開発でクラスパスが正しく設定されていないと、コンパイルは成功しても、実行時に「クラスが見つからない」というエラーが発生します。ここでは、代表的な3つのエラーとその解決方法を解説します。

ClassNotFoundExceptionが出る原因と対処法

ClassNotFoundException は、プログラム実行中に、動的にクラスをロードしようとしたが見つからなかった場合に発生する例外(チェック例外)です。

発生する主な場面

  • Class.forName("com.example.Hoge") のように、リフレクションを使ってクラス名を文字列で指定してロードしようとした時
  • JDBCドライバのロード時(例: Class.forName("com.mysql.cj.jdbc.Driver")

原因

  • クラスパスが通っていない: 必要なJarファイル(例:MySQLのJDBCドライバのJar)が、実行時のクラスパス(-cp やIDEの設定)に含まれていない
  • クラス名のタイプミス: Class.forName() に渡すクラス名(完全修飾名)が間違っている

対処法

  • 実行時のクラスパス設定を再確認し、必要なJarファイルやクラスの出力先ディレクトリが正しく含まれているか確認する
  • IDEを使っている場合は、プロジェクトの依存関係(ビルドパス)の設定を見直す
  • クラス名が正しいか(パッケージ名、大文字小文字)をしっかり確認する

NoClassDefFoundErrorの仕組みと解決アプローチ

NoClassDefFoundError は、コンパイル時には確かに存在していたクラスが、実行時に見つからなかった場合に発生するエラーです。

ClassNotFoundException と似ていますが、こちらはより深刻な問題を示唆することが多いです。JVMが、あるクラスをロードしようとした際、そのクラスAが依存している別のクラスの定義が見つからない、という状況で発生します。

原因

  • 実行時のみに存在する依存関係の欠如: コンパイル時はクラスBが存在したが、実行時のクラスパスにはクラスB(またはそれを含むJar)が含まれていなかった。
  • 静的初期化子でのエラー: クラスBの静的初期化ブロック(static { ... })で例外が発生し、クラスBのロードに失敗した。JVMは一度ロードに失敗したクラスを二度とロードしようとしないため、次にクラスAがクラスBを使おうとした瞬間に NoClassDefFoundError が発生する。

解決アプローチ

  • ClassNotFoundException と同様に、実行時のクラスパス設定を徹底的に見直します。
  • エラーメッセージに「caused by(原因)」として別の例外(例: ExceptionInInitializerError)が表示されていないか確認する。もし表示されていれば、そちらが根本原因。
  • 依存しているライブラリが、さらに別のライブラリに依存している場合がある。その「孫」ライブラリが不足していないか確認する。

パスの区切り文字・相対パス設定ミスによるエラー

非常に初歩的ですが、最も多いミスの一つです。

  • 区切り文字の間違い:前述の通り、Windowsはセミコロン(;)、Linux/Macはコロン(:)です。開発環境(Mac)と本番環境(Windowsサーバー)が異なる場合などに、この違いを忘れてスクリプトを組むとエラーとなる
  • 相対パスの基点ミス:java -cp ../lib/hoge.jar Main のように相対パスを指定した場合、その「基点」は java コマンドを実行したカレントディレクトリです。実行する場所(ディレクトリ)が変われば、相対パスの意味も変わってしまいます。スクリプトなどで実行する場合は、スクリプトの場所を基準にした絶対パスに変換するか、java コマンドを実行するディレクトリを固定する工夫が必要
  • タイプミス:単純なスペルミス(lib を libs と書くなど)もエラーの原因

クラスパスとモジュールシステム(Java 9以降)の違い

Java 9 からJigsawプロジェクトの一環でモジュールシステムが導入され、「モジュールパス」という概念が登場しました。

クラスパス方式とモジュールパス方式の違い

項目クラスパス方式(従来)モジュールパス方式(Java 9以降)
基本構造すべてのクラスとJarが一つの大きな空間(クラスパス)に置かれるコードを「モジュール」という単位で分割する
設定ファイル特になしmodule-info.java を持つ
依存関係の宣言明示的な宣言なしrequires で依存モジュールを明示する
公開範囲の制御クラスパス上にあれば public クラスは基本的に参照可能exports で公開パッケージを明示する
カプセル化不十分(public なら基本的にアクセス可能)強化される(未exportsパッケージは外部からアクセス不可)
バージョン衝突同一ライブラリの複数バージョン混在で問題が起きやすい依存関係が明確になり衝突の管理がしやすい

モジュールパスを使うべきケース・使わない方がいいケース

モジュールパスを使うべきケース

  • Java9以降の環境で、新規に大規模なアプリケーションを開発する場合
  • 厳密なカプセル化や、信頼性の高い依存関係の管理が求められる場合
  • 将来的にJLink(必要なモジュールだけを組み込んだカスタムJREを作成するツール)を使いたい場合

使わない方がいいケース(クラスパスを使い続けるケース)

  • 既存のJava 8以前のプロジェクトを保守する場合
  • 使用するライブラリの多くが、まだモジュールシステムに対応していない(module-info.java を持たない)場合
  • 小規模なアプリケーションや、学習目的の場合

現在のところ、多くのライブラリはクラスパス方式(自動モジュールとして動作)でも利用可能なため、無理にモジュール化する必要はありません。しかし、Javaの今後の方向性として、モジュールシステムの存在は知っておくべきです。

クラスパスを正しく設計するためのベストプラクティス

クラスパスの手動管理は、ミスが多く非効率です。特にプロジェクトが大きくなるにつれて、依存するJarファイルは数十、数百に達することもあります。

Jar管理を簡単にするためのMaven・Gradleの活用

現代のJava開発では、MavenGradle といった「ビルドツール(依存関係管理ツール)」を使うのが常識です。

これらのツールは、クラスパス管理における以下の問題を解決します。

  1. 依存関係の宣言:pom.xml (Maven) や build.gradle (Gradle) という設定ファイルに、「どのライブラリ(例: MySQL Connector)の、どのバージョン(例: 8.0.30)が必要か」を記述する
  2. ライブラリの自動ダウンロード:ビルドツールが、インターネット上のリポジトリ(Maven Centralなど)から、必要なJarファイルを自動でダウンロードしてくれる
  3. 推移的依存の解決:MySQL Connectorが、さらに別のライブラリ(例: Protobuf)を必要とする場合(推移的依存)、それも自動でダウンロードしてくれる
  4. クラスパスの自動設定:コンパイル時や実行時に、ダウンロードしたすべてのJarファイルを含む、適切なクラスパスを自動で設定して java コマンドを実行してくれる

開発者は、pom.xml を書くだけで、-cp オプションの長い呪文から解放されます。

クラスパス依存によるトラブルを避けるためのプロジェクト構成

ビルドツールを使う場合でも、標準的なプロジェクト構成に従うことがトラブル回避の鍵です。

  • Mavenの標準ディレクトリ構成:
    • src/main/java: 自作のJavaソースコード(.java
    • src/main/resources: 設定ファイルなど(クラスパスのルートにコピーされる)
    • src/test/java: テストコード
    • src/test/resources: テスト用設定ファイル
    • target/classes: コンパイルされた .class ファイル(自動生成)

この構成に従うだけで、IDEやビルドツールは「どこにソースコードがあり、どこにクラスファイルが出力されるか」を自動で認識し、クラスパスを適切に設定してくれます。

大規模開発でのクラスパス管理の考え方

大規模なシステムでは、システム全体を機能ごとに複数の「モジュール(プロジェクト)」に分割します。

例えば、「Web層」「ビジネスロジック層」「データアクセス層」のように分けます。

この場合、Web層はビジネスロジック層に依存し、ビジネスロジック層はデータアクセス層に依存します。

MavenやGradleは、このようなモジュール間の依存関係も管理できます。Web層のクラスパスには、ビジネスロジック層のJar(または classes)と、データアクセス層のJarが自動で含まれるように設定可能です。

これにより、各モジュールは必要な依存関係だけを持つことができ、クラスパスが不必要に肥大化するのを防ぎます。

まとめ:Javaのクラスパスを理解すると開発効率が上がる

クラスパスの仕組みを理解することで、Javaがどのようにコードを見つけて動くかの根幹が分かります。

クラスパス理解で防げるトラブル

クラスパスを正しく理解していれば、ClassNotFoundExceptionNoClassDefFoundError といった、Java初学者が最も時間を浪費するエラーに、冷静に対処できるようになります。

「なぜこのJarが必要なのか」「IDEは裏で何をしているのか」が分かれば、エラーメッセージを見た瞬間に、原因が「設定ミス」なのか「ライブラリ不足」なのか、あるいは「バージョンの競合」なのか、あたりをつけられます。

この「あたりをつける」スピードが、開発効率に直結するのです。

  • この記事を書いた人
  • 最新記事

トム

・都内自社開発企業勤務/Javaバックエンドエンジニア
/Java歴10年以上 ・首都圏在住30代
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎 詳細なプロフィール

-Java入門