0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Java用語、結局なんだっけ? #1】環境・基盤編 ― JDK・JRE・JVM・クラスパス・アノテーション etc.

0
Posted at

はじめに

株式会社Good Labでエンジニアをしている コータロー です。
日々、Java・SQL・Gitなどの技術情報や、新人エンジニア向けの学習ノウハウ、
AI活用についての情報を発信しています。

Good Labについて気になった方は、コーポレートサイトもぜひご覧ください。
コーポレートサイト

新人〜2年目のJavaエンジニアが、現場で 「聞いたことはあるけど、ちゃんと説明しろと言われると困る」 という用語を一掃するシリーズの第1回です。

テーマ
#1(本記事) 環境・基盤編(JDK / JRE / JVM、クラスパス、JAR、アノテーション、ジェネリクス、リフレクション)
#2 DB接続編(JDBC、ドライバー、コネクション、コネクションプール、データソース、トランザクション)
#3 Web/サーバー編(サーブレット、JSP、Tomcat、WAR、フィルタ、Webコンテナ、ステートフル/ステートレス)
#4 例外・スレッド編(checked / unchecked、try-with-resources、スレッド、synchronized、volatile、デッドロック)
#5 モダンJava編(ラムダ、ストリーム、Optional、関数型インターフェース、メソッド参照、record)
#6 フレームワーク編(Spring / Spring Boot、DI / IoC、Bean、AOP、Lombok、JPA)
#7 ビルド・運用編(Maven / Gradle、プラグイン、依存性、JUnit、Mockito、JAR/WAR/EAR)

第1回は 環境・基盤編 です。Javaのコードを書く前に必ず触れる「土台」のワードを一気に整理します。


この記事のゴール

この記事を読み終わると、以下ができるようになります。

  • JDK / JRE / JVM の違いを 一言で説明 できる
  • 「クラスパス」「JAR」「アノテーション」「ジェネリクス」「リフレクション」を、新人にも分かるレベルで説明できる
  • これらが 「Javaプログラムが動くまで」のどこに登場するか が頭の中で繋がる

全体像:Javaプログラムが動くまで

まず、Javaのコードが動くまでの流れと、登場する用語の関係を整理します。

[あなたが書く]           [変換]              [実行]
  Foo.java       →    Foo.class      →    実行結果
   (ソース)         (バイトコード)         (出力)
      ↑                  ↑                  ↑
      |                  |                  |
   JDKに含まれる       JDKに含まれる         JREに含まれる
   javac で変換        javac の出力         JVM が実行
                                            ↑
                                       「どこから.classを探すか」
                                       = クラスパス

ここで登場する用語を 6つに分けて 解説していきます。


① JDK / JRE / JVM ― 入れ子の3階層

一言で言うと

用語 一言で 用途
JVM(Java Virtual Machine) Javaを実行する「仮想マシン」 実行
JRE(Java Runtime Environment) JVM + 標準ライブラリ 実行
JDK(Java Development Kit) JRE + コンパイラなどの開発ツール 開発

関係性

┌─────────────────────────────┐
│         JDK                 │  ← 開発者が使う
│  ┌──────────────────────┐   │
│  │       JRE            │   │  ← 実行に必要な最小セット
│  │  ┌────────────────┐  │   │
│  │  │     JVM        │  │   │  ← 実行エンジン
│  │  └────────────────┘  │   │
│  │  + 標準ライブラリ    │   │
│  └──────────────────────┘   │
│  + javac (コンパイラ)        │
│  + jar、javadoc、jdb など    │
└─────────────────────────────┘

よくある誤解

  • 「JDK」と「Eclipse」を混同する:EclipseはIDE(開発支援ツール)、JDKはJava本体。別物。
  • 「JVMはマシンの中に1個だけ」と思う:実際は、java コマンドを実行するたびに新しいJVMプロセスが起動する。

補足:Java 11以降の JRE 配布事情

Java 11以降、Oracle / OpenJDK は JRE 単独配布をやめました
代わりに以下のいずれかが推奨されています:

  • JDK をそのままインストール(実行用途でもOK)
  • jlink コマンドで必要最小限のランタイムを自作

「JREだけ欲しい」と思っても、Java 11以降は JDK をインストールするのが一般的になりました。

確認方法

$ java -version
openjdk version "21.0.10" 2026-01-20

$ javac -version
javac 21.0.10

java が動けばJREはある。javac も動けばJDKまで入っている、という見分け方です。


② クラスパス ― 「.class をどこから探すか」のリスト

一言で言うと

**JVM が .class ファイルや JAR を探しに行く「ディレクトリ・JARファイルのリスト」**です。
Windowsで言う「PATH」のJava版だと思えばOKです。

何が問題か

Javaは「ソースコード(.java)→ バイトコード(.class)→ 実行」という流れで動きます。
実行時にJVMは .class ファイルを探す必要があります。「どこを探すか」を教えるのがクラスパスです。

動作例

# プロジェクト構造
project/
├── src/com/example/Greeter.java
└── build/com/example/Greeter.class  ← コンパイル後

# コンパイル:-d でビルド先を指定
$ javac -d build src/com/example/Greeter.java

# 実行:-cp(または -classpath)でクラスパスを指定
$ java -cp build com.example.Greeter
Hello from Greeter!

-cp build.classbuild/ 配下にあるよ」 とJVMに教えています。

複数指定(区切り文字に注意)

# macOS / Linux(コロン区切り)
$ java -cp build:lib/mysql-connector.jar com.example.App

# Windows(セミコロン区切り)
> java -cp build;lib\mysql-connector.jar com.example.App

よくある誤解

  • 「クラスパス=環境変数 CLASSPATH」:環境変数も存在しますが、現代では -cp オプションやビルドツール(Maven / Gradle)が管理するのが基本。環境変数 CLASSPATH は設定しない方が安全です。
  • 「クラスパスにソースの .java を指定する」:クラスパスは .class ファイルとJARを探す場所。.java ではない。

③ JAR ファイル ― Javaの「圧縮配布形式」

一言で言うと

.class ファイルや設定ファイルを1つにまとめた、Java版のZIPファイルです。
拡張子は .jar、実体はZIP形式。

何のためにある?

  • 1つのファイルで配布できる(数百個の .class をまとめる)
  • 実行可能にできる(java -jar foo.jar で動かせる)
  • ライブラリとして他のプロジェクトから使える

作成・実行の流れ

# マニフェストファイル(Main-Classを指定)
$ cat META-INF/MANIFEST.MF
Manifest-Version: 1.0
Main-Class: com.example.Greeter

# JAR作成
$ jar cfm greeter.jar META-INF/MANIFEST.MF -C build .

# 実行
$ java -jar greeter.jar
Hello from Greeter!

# 中身を確認
$ jar tf greeter.jar
META-INF/
META-INF/MANIFEST.MF
com/example/Greeter.class

マニフェスト(MANIFEST.MF)とは

JARに含まれるメタ情報を書くファイル。
最低限 Main-Classjava -jar で起動するクラス)を書きます。
これがないと java -jar で実行できません。

よくある誤解

  • 「JAR ファイルは Java 専用の圧縮形式」:実体は普通のZIP。unzip でも展開できます。
  • 「JARファイルにソースコード(.java)が含まれる」:通常は .class(バイトコード)が含まれます。ソース付きJARは別途 -sources.jar として配布されることが多い。
  • 「.war や .ear もJARと同じ」:構造は似ているが用途が違う。.war はWebアプリ、.ear はEnterpriseアプリ用(#7で詳しく)。

④ アノテーション ― コードに付ける「目印」

一言で言うと

@ で始まる、コードに付けるメタ情報の目印です。
コンパイラやフレームワークが、この目印を見て特別な処理をします。

よく見る標準アノテーション

アノテーション 何をする
@Override 「このメソッドは親クラスのメソッドをオーバーライドしている」と明示。ミスがあるとコンパイルエラー
@Deprecated 「このメソッドは非推奨」を伝える。使用箇所が警告される
@FunctionalInterface 「これは関数型インターフェースとして使う」と明示
@SuppressWarnings 「この警告は無視してOK」と明示

コード例

public class AnnotationDemo {
    public static void main(String[] args) {
        Animal animal = new Dog();
        System.out.println(animal.speak());
    }
}

class Animal {
    public String speak() {
        return "...";
    }
}

class Dog extends Animal {
    @Override  // ← 親のspeak()をオーバーライド
    public String speak() {
        return "ワン";
    }
}

出力:

ワン

もし @Override を書いた状態で メソッド名を speak から speek に書き間違えた とすると、コンパイルエラー になります。
これが @Override の最大の価値:「うっかりタイポ」を実行前に検出できること。

カスタムアノテーション(フレームワークでよく見る)

Spring などのフレームワークは、独自のアノテーションを大量に提供しています。

@RestController
@RequestMapping("/users")
public class UserController {

    @GetMapping("/{id}")
    public User findUser(@PathVariable Long id) {
        // ...
    }
}

このアノテーションをフレームワークが リフレクション(後述) を使って読み取り、ルーティング設定などを自動でやってくれます。

よくある誤解

  • 「アノテーションはコメントの一種」:違う。コンパイラやフレームワークが認識する、メタ情報 です。
  • 「アノテーションを付けると処理が変わる」:アノテーション単体では何もしない。それを 読み取る側のコード(フレームワーク等) が処理を変える。

⑤ ジェネリクス ― 型を「引数のように渡す」仕組み

一言で言うと

List<String><String> の部分
クラスやメソッドが扱う「型」を 後から指定 できる仕組みです。

何が嬉しい?

ジェネリクス導入前(Java 5以前)はこう書いていました:

// 昔のJava(Java 5以前)
List names = new ArrayList();
names.add("田中");
String name = (String) names.get(0);  // ← キャストが必要

ジェネリクスを使うとこう書けます:

// 現代Java
List<String> names = new ArrayList<>();
names.add("田中");
String name = names.get(0);  // ← キャスト不要・型安全

メリット:

  • 型安全names.add(123) のように違う型を入れるとコンパイルエラー
  • キャスト不要:取り出した値の型が決まっている
  • 可読性:「このリストには文字列が入る」と一目で分かる

自分でジェネリクスなクラスを作る

class Box<T> {  // ← T は型パラメータ(プレースホルダ)
    private final T value;
    public Box(T value) { this.value = value; }
    public T getValue() { return value; }
}

// 使う側
Box<Integer> intBox = new Box<>(42);
Box<String> strBox = new Box<>("Hello");
System.out.println(intBox.getValue());  // 42
System.out.println(strBox.getValue());  // Hello

Box<T>T「あとで型を入れてね」というプレースホルダ
Box<Integer> と書いた瞬間に、すべての TInteger に置き換わります。

型パラメータの慣習

文字 意味
T Type(型)一般
E Element(コレクションの要素)
KV Key、Value(Map用)
R Return(戻り値の型)

よくある誤解

  • List<int> が書けない」:その通り。プリミティブ型(int、boolean等)は使えない。ラッパークラス(IntegerBoolean 等)を使う:List<Integer>
  • <?> ってなに?」:ワイルドカード。「型は何でもいい」を表す。List<?> は「何かのリスト」。

⑥ リフレクション ― 実行時にクラス情報を覗く仕組み

一言で言うと

実行中に、クラスやメソッドの情報を取り出して操作する仕組みです。
通常は「コンパイル時」に決まっているメソッド呼び出しを、「実行時」に動的に行えるのが特徴。

コード例

import java.lang.reflect.Method;

public class ReflectionDemo {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("java.lang.String");
        System.out.println("クラス名: " + clazz.getName());

        Method lengthMethod = clazz.getMethod("length");
        String hello = "Hello";
        Object result = lengthMethod.invoke(hello);
        System.out.println("hello.length() = " + result);
    }
}

出力:

クラス名: java.lang.String
hello.length() = 5

hello.length()直接呼ぶ代わりに、Method オブジェクト経由で呼び出している のがポイントです。

何のために使う?

新人〜2年目が 業務コードでリフレクションを直接書く機会はほぼゼロ です。
ただし、以下のような フレームワークの内部 で大活躍しています:

  • Spring:@Autowired のフィールドに依存を注入する
  • Jackson:JSON ⇔ オブジェクトの変換
  • JUnit:@Test が付いたメソッドを自動で実行する
  • Lombok:アノテーションから getter/setter を自動生成

「フレームワークがどうやって @RequestMapping を認識しているか」の答えが、リフレクションです。

よくある誤解

  • 「自分でリフレクションを書く必要がある」:基本ない。「フレームワークが使っている裏側の仕組み」 として理解しておけば十分。
  • 「リフレクションは遅い」:直接呼び出しよりは遅いが、現代のJVMでは多くの場合無視できるレベル。

用語まとめ早見表

用語 一言で いつ使う / 出会う
JVM Javaを実行する仮想マシン java コマンド実行時
JRE JVM + 標準ライブラリ アプリ実行環境
JDK JRE + 開発ツール(javac等) 開発者がインストール
クラスパス .class を探す場所のリスト java -cp で指定、Maven等が自動管理
JAR Javaの圧縮配布形式 アプリ配布、ライブラリ取り込み
アノテーション @ で始まるメタ情報 @Override、Spring等のフレームワーク
ジェネリクス 型を引数化する仕組み List<String>、自作のジェネリッククラス
リフレクション 実行時にクラス情報を操作 フレームワーク内部(直接書くことは稀)

現場あるある誤解集

❌ 誤解 ⭕ 正しい理解
「JDKってEclipseのこと?」 EclipseはIDE。JDKはJava本体(コンパイラ+実行環境)
「JAR = 暗号化された秘密のファイル」 ただのZIPファイル。unzip で展開可能
「アノテーション付けたら勝手に動く」 単体では何もしない。読み取る側(フレームワーク)が処理する
List<int> で整数リスト」 プリミティブ型は使えない。List<Integer> と書く
「リフレクションは普通のコードで使う」 業務コードではほぼ使わない。フレームワークが裏で使う
「環境変数CLASSPATHを設定すべき」 現代では設定しない方が安全。-cp や ビルドツール任せ
「JRE単独でJava 17をインストールできる」 できない。Java 11以降はJDKに含まれる形のみ

演習問題

理解度チェックです。考えてから模範解答を見てください。

問題1:JDK / JRE / JVM の関係 ⭐

次の文章の空欄を埋めてください。

「Javaのコードを書いてビルドしたい開発者は ___ をインストールする。
一方、ビルド済みのJavaアプリを動かすだけのユーザーは ___ があれば動く。
どちらも内部では、Javaのバイトコードを実行する ___ が動いている。」

模範解答

「Javaのコードを書いてビルドしたい開発者は JDK をインストールする。
一方、ビルド済みのJavaアプリを動かすだけのユーザーは JRE があれば動く。
どちらも内部では、Javaのバイトコードを実行する JVM が動いている。」

ポイント:JDK ⊃ JRE ⊃ JVM の包含関係を押さえる。Java 11以降はJREの単独配布がなくなったため、開発者でなくてもJDKをインストールするのが一般的になりました。


問題2:クラスパスとJAR ⭐

build/ ディレクトリに com/example/App.class があるとき、これを実行するコマンドはどれですか?

  • A. java com.example.App
  • B. java -cp build com.example.App
  • C. java -cp build/com/example/App.class
  • D. java build/com/example/App.class
模範解答

正解:B

ポイント

  • -cp build で「build/ 配下を探してね」とJVMに伝える
  • 実行対象は 完全修飾クラス名com.example.App)で指定する
  • A は build/ をクラスパスに入れていないのでクラスを見つけられない
  • C, D は .class ファイルそのものを指定しているが、java コマンドは「クラス名」を期待する

問題3:ジェネリクスとアノテーション ⭐

次のコードのうち、コンパイルエラーになる のはどれですか?

class Pair<A, B> {
    private final A first;
    private final B second;
    Pair(A first, B second) { this.first = first; this.second = second; }
    A getFirst() { return first; }
    B getSecond() { return second; }
}

public class Sample {
    public static void main(String[] args) {
        Pair<String, Integer> p1 = new Pair<>("田中", 30);          // ①
        Pair<int, String> p2 = new Pair<>(1, "佐藤");               // ②
        Pair<String, String> p3 = new Pair<>("Hello", 100);         // ③
    }
}
模範解答

正解:② と ③

解説

  • ② はNG:ジェネリクスの型パラメータには プリミティブ型(int等)を使えませんPair<Integer, String> と書く必要があります。
  • ③ もNGPair<String, String> と宣言したのに、第2引数に 100(Integer)を渡しています。型が一致しないのでコンパイルエラー。
  • ① はOKPair<String, Integer> の型と、引数 "田中"(String)、30(Integer)が一致しています。

ポイント

  • ジェネリクスの型安全性は コンパイル時 に検査される
  • プリミティブ型は使えないので ラッパークラスIntegerBoolean 等)を使う

まとめ

今回扱った6つの用語のおさらいです。

  1. JDK / JRE / JVM:開発者用キット/実行環境/仮想マシン。入れ子の3階層
  2. クラスパス.class ファイルを探す場所のリスト。-cp で指定
  3. JAR:Javaの圧縮配布形式。ZIPと同じ。マニフェストで実行可能に
  4. アノテーション@ で始まるメタ情報。フレームワークが読み取って動作する
  5. ジェネリクス:型を引数化する仕組み。List<String><> 部分
  6. リフレクション:実行時にクラス情報を操作。フレームワークの内部で大活躍

これらは 業務でJavaを書く上での「基礎の基礎」 です。
新人のうちに「人に説明できる」レベルにしておくと、フレームワークの動作原理がスッと頭に入ります。


次回予告

次回(#2)は DB接続編 です。

  • JDBC とは何か(仕様 vs 実装)
  • ドライバーって結局何をしているの?
  • コネクション・コネクションプール・データソースの違い
  • トランザクションの基本

を、現場で出会う実装例とともに解説します。


参考


@kotaro_ai_lab
AI活用や開発効率化について発信しています。フォローお気軽にどうぞ!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?