はじめに
株式会社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 で 「.class は build/ 配下にあるよ」 と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-Class(java -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> と書いた瞬間に、すべての T が Integer に置き換わります。
型パラメータの慣習
| 文字 | 意味 |
|---|---|
T |
Type(型)一般 |
E |
Element(コレクションの要素) |
K、V
|
Key、Value(Map用) |
R |
Return(戻り値の型) |
よくある誤解
-
「
List<int>が書けない」:その通り。プリミティブ型(int、boolean等)は使えない。ラッパークラス(Integer、Boolean等)を使う: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>と書く必要があります。 -
③ もNG:
Pair<String, String>と宣言したのに、第2引数に100(Integer)を渡しています。型が一致しないのでコンパイルエラー。 -
① はOK:
Pair<String, Integer>の型と、引数"田中"(String)、30(Integer)が一致しています。
ポイント:
- ジェネリクスの型安全性は コンパイル時 に検査される
- プリミティブ型は使えないので ラッパークラス(
Integer、Boolean等)を使う
まとめ
今回扱った6つの用語のおさらいです。
- JDK / JRE / JVM:開発者用キット/実行環境/仮想マシン。入れ子の3階層
-
クラスパス:
.classファイルを探す場所のリスト。-cpで指定 - JAR:Javaの圧縮配布形式。ZIPと同じ。マニフェストで実行可能に
-
アノテーション:
@で始まるメタ情報。フレームワークが読み取って動作する -
ジェネリクス:型を引数化する仕組み。
List<String>の<>部分 - リフレクション:実行時にクラス情報を操作。フレームワークの内部で大活躍
これらは 業務でJavaを書く上での「基礎の基礎」 です。
新人のうちに「人に説明できる」レベルにしておくと、フレームワークの動作原理がスッと頭に入ります。
次回予告
次回(#2)は DB接続編 です。
- JDBC とは何か(仕様 vs 実装)
- ドライバーって結局何をしているの?
- コネクション・コネクションプール・データソースの違い
- トランザクションの基本
を、現場で出会う実装例とともに解説します。
参考
- Java Development Kit(Oracle公式)
- Java言語仕様(JLS)
- The Java® Tutorials - Generics
- The Java® Tutorials - Annotations
@kotaro_ai_lab
AI活用や開発効率化について発信しています。フォローお気軽にどうぞ!