はじめに
Javaでオブジェクト指向を学ぶなら、classで型を作り、newで実体を生成し、methodで振る舞いを分ける流れを先に押さえると理解しやすくなります。その土台があると、extends、interface、private、publicの役割も個別の暗記ではなく設計上の選択として整理できます。
初心者がつまずきやすいのは、文法を覚えているのに、どの単位でデータと処理をまとめるか判断できない点です。そのため、最小のコードから始め、クラス、オブジェクト、継承、ポリモーフィズム、カプセル化、抽象化を順に接続して考える構成にしているのが基本です。
- Java 21 LTS
- JDK 21 / JShell または任意のIDE
- Spring Boot例は Spring Boot 3.x 系の構文を前提
公式ドキュメントで仕様を確認する場合は、OracleのObject-Oriented Programming Conceptsと、Java SE APIのjava.lang.Objectが一次情報として参照できます。一方、実務寄りの設計では、オーバーライドの考え方やList型の扱いも同時に確認すると、コード例の意図がつながりやすいです。
- Javaの基本構文と
mainメソッドの位置づけ - クラス、オブジェクト、コンストラクタの関係
- 継承、ポリモーフィズム、カプセル化、抽象化の使い分け
- 例外処理、ライブラリ、フレームワークの実装パターン
- オブジェクト指向コードを拡張しやすく保つ設計の考え方
Javaとは
Javaは、ソースコードをjavacで.classファイルへ変換し、JVM上で実行するプログラミング言語です。この仕組みにより、OSごとの違いをJVMが吸収し、同じコードを複数の環境で動かしやすくしています。
一般に、Javaは業務システム、Webアプリケーション、Android関連開発、バッチ処理、教育用途で使われます。その背景には、静的型付け、豊富な標準ライブラリ、長期サポート版の存在、IDEによる補完やリファクタリング支援があるのが目安です。
Javaの特性と歴史
Javaは1995年にSun Microsystemsから公開され、現在はOracleが仕様と実装の中心的な役割を担っているのが基本です。その歴史の中で、generics、enum、lambda、Stream、recordなどが追加され、表現力は段階的に広がりました。
ただし、歴史を覚えるだけでは実装力に直結しません。Javaらしい設計を理解するには、Objectを頂点とする型の階層、packageによる分類、importによる参照、access modifierによる公開範囲の制御を関連づけて読む必要があります。
Javaの基本構文
Javaのプログラムは、多くの場合public classの中にpublic static void main(String[] args)を置いて開始するのがポイントです。このmainメソッドが実行入口になり、System.out.printlnなどの処理が上から順に評価されます。
結果: 期待される出力は「Hello Java」です。
このコードでは、Mainがクラス名、String[] argsがコマンドライン引数、printlnが改行付き出力を担当するのが目安です。一方、ファイル名とpublic class名は一致させる必要があり、例ではMain.javaとして保存する形になるのが一般的です。
基本構文の中心には、int、double、boolean、Stringなどの型、if、for、while、returnなどの制御構文があります。その理解が進むと、ListやMapのようなコレクションも扱いやすくなるでしょう。
💡 Tips: varはローカル変数の型推論で使えますが、型が読み取りにくくなる場面では明示的な型名のほうが保守しやすい場合があります。
オブジェクト指向とは
オブジェクト指向は、データと処理をひとまとまりの部品として扱う設計思想です。Javaでは、その部品の設計図をclass、設計図から作られた実体をobjectやinstanceと呼びますし、ここがポイントです。
具体的には、会員を表すUserクラスなら、名前やメールアドレスをfieldとして持ち、表示名を返す処理をmethodとして持たせますし、ここがポイントです。そのため、関連する値と振る舞いが分散しにくくなり、変更の影響範囲を追いやすくなります。
オブジェクト指向の基本理念
オブジェクト指向の中心には、クラスとオブジェクト、継承、ポリモーフィズム、カプセル化、抽象化があるのが現実的です。これらは別々の用語に見えますが、目的は変更に強い構造を作ることに集約されます。
クラスとオブジェクトは、型と実体の関係です。一方、継承は共通部分を親クラスへ寄せ、ポリモーフィズムは同じ呼び出しで異なる動作を選べるようにするのがポイントです。
カプセル化ではprivateフィールドを直接触らせず、getterやsetter、または目的別メソッドを通じて状態を変えますが、これは押さえたい点です。抽象化では細かい内部処理を隠し、呼び出し側に必要な操作だけを見せるのが基本です。
オブジェクト指向のメリットとデメリット
オブジェクト指向の利点は、データと処理のまとまりが明確になり、同じ概念を複数箇所で書き直す場面を減らせる点です。その結果、画面、API、バッチ処理が同じdomain modelを共有する設計も取りやすくなります。
ただし、すべてをクラス階層で表そうとすると、継承が深くなりすぎたり、責務の境界が曖昧になったりします。そのため、共通化したい理由が弱い場合は、継承よりもcompositionやinterfaceを選ぶほうが現実的だと言えるでしょう。
interfaceと委譲を検討すると設計が硬くなりにくいです。| 項目 | Javaでの形 | 主な役割 | 注意点 | 関連コード |
|---|---|---|---|---|
| クラス | class | 設計図を作る | 責務を広げすぎない | class User |
| オブジェクト | new | 実体を生成する | 状態の初期化を忘れない | new User() |
| フィールド | private String name | 状態を保持する | 直接公開を避ける | private |
| メソッド | void run() | 振る舞いを表す | 目的を名前で示す | return |
| コンストラクタ | User(...) | 初期状態を作る | 不完全な生成を避ける | this.name |
| アクセス修飾子 | public/private | 公開範囲を制御する | 広げすぎない | protected |
| 継承 | extends | 共通処理を受け継ぐ | 階層を深くしない | super() |
| インターフェイス | interface | 契約を定める | 実装詳細を含めすぎない | implements |
| 抽象クラス | abstract class | 共通実装を持つ土台 | 多重継承はできない | abstract |
| オーバーライド | @Override | 親の動作を置き換える | シグネチャを合わせる | toString() |
| オーバーロード | 同名別引数 | 呼び出し形を増やす | 曖昧な引数を避ける | print(int) |
| ポリモーフィズム | 親型参照 | 呼び出し側を共通化する | 型判定に頼りすぎない | Vehicle v |
| カプセル化 | private + メソッド | 状態変更を制限する | 単純なsetter乱用を避ける | getName() |
| 抽象化 | interface | 必要な操作だけ見せる | 名前を具体化しすぎない | Repository |
| 例外 | try/catch | 異常系を扱う | 握りつぶさない | throw |
| ジェネリクス | List<String> | 型安全に扱う | raw型を避ける | <T> |
| コレクション | ArrayList | 複数件を保持する | 用途で型を選ぶ | Map |
| ラムダ式 | x -> x + 1 | 処理を値のように渡す | 複雑化を避ける | Predicate |
| Stream | stream() | 集合処理を連結する | 副作用を減らす | filter |
| record | record User(...) | 値オブジェクトを簡潔に作る | 可変状態に向かない | record |
| enum | enum Status | 定数集合を表す | 文字列比較を減らす | ACTIVE |
| パッケージ | package | 名前空間を分ける | 循環依存に注意する | import |
| static | static | クラスに属する値を扱う | 状態共有を増やしすぎない | static final |
| final | final | 再代入や継承を制限する | 意図を明確に使う | final int |
| null | null | 参照なしを表す | NullPointerExceptionを招く | Optional |
| Optional | Optional<T> | 値の有無を表す | フィールド乱用を避ける | orElse |
| equals | equals() | 値の同一性を判定する | hashCode()と合わせる | Objects.equals |
| テスト | JUnit | 振る舞いを検証する | 境界値を含める | @Test |
| ビルド | Maven/Gradle | 依存関係を管理する | バージョンを固定する | pom.xml |
| 起動 | java Main | クラスを実行する | クラスパスを確認する | -cp |
Javaにおけるオブジェクト指向プログラミングの理解
Javaのオブジェクト指向は、文法だけでなく設計単位の作り方として理解する必要があります。たとえば車を扱うなら、速度という状態と加速という処理を同じCarクラスへ集めると、利用側は「車を加速させる」という自然な操作で扱えます。
クラスとオブジェクトの定義
具体的には、Carクラスにbrandとspeedを持たせ、accelerateメソッドで速度を変える形にできると理解できるのが現実的です。このとき、constructorで初期値を受け取ると、生成直後から意味のある状態を保てます。
結果: 期待される出力は「Toyotaの現在速度: 10km/h」です。
この例では、利用側がspeedを直接変更せず、accelerateを通じて状態を進めます。そのため、速度の増え方を変更したい場合でも、呼び出し側のmainは大きく変えずに済みます。
継承とポリモーフィズム
継承は、共通する状態や処理を親クラスへ置き、差分だけを子クラスへ書く仕組みです。一方、ポリモーフィズムは、親型やインターフェイス型で受け取りながら、実体ごとのoverrideされた処理を呼び分けますし、これが一つの目安です。
結果: 期待される出力は「車: 10km/h」と「自転車: 2km/h」です。
このとき、配列の型はVehicle[]ですが、実際に呼ばれる処理はCarとBicycleで異なります。こうした性質により、利用側は種類ごとの分岐を増やさずに処理を広げられます。
カプセル化と抽象化
カプセル化では、状態を外部に直接公開せず、意味のある操作だけを公開すると覚えるとよいでしょう。たとえば年齢を持つPersonであれば、負の値を入れられないようにchangeAge内で判定する形が考えられますが、これは押さえたい点です。
結果: 期待される出力は「20」です。
その設計では、ageの値が不正になりにくく、バグの入口をクラス内に閉じ込められます。抽象化はこの考えを一段進め、利用側が内部の条件分岐や計算式を知らなくても目的の操作を呼べる状態を作ります。
実践!Javaでオブジェクト指向プログラムを作成
オブジェクト指向を実装へ落とすときは、対象を名詞で切り出し、状態をフィールドへ置き、振る舞いをメソッドへ移すると考えられますし、これが一つの目安です。そのうえで、生成時に必要な値をコンストラクタへ集めると、途中で壊れた状態になりにくい構造になります。
開発環境の設定
Javaを書くには、JDKとエディタまたはIDEが必要です。javacとjavaだけでも動かせますが、学習が進むとIntelliJ IDEA、Eclipse、VS Codeなどの補完機能が役立ちます。
基本的には、java -versionでJDKの認識を確認し、Main.javaを作成してjavac Main.java、java Mainの順に実行すると言えるでしょう。依存ライブラリを使う段階では、MavenやGradleでclasspathを管理する構成へ移るのが自然です。
サンプルコード1:基本的なクラスの作成と使用
基本的なクラスでは、フィールド、コンストラクタ、値を返すメソッドをまとめますが、覚えておくと役立つでしょう。次のPersonは、名前と年齢を生成時に受け取り、表示用の文字列を返す小さなモデルです。
結果: 期待される出力は「名前: 山田太郎, 年齢: 30歳」です。
このコードでは、finalによりnameとageの再代入を防いでいます。一方、年齢を後から変更したい要件があるなら、changeAgeのような目的を持つメソッドを追加し、値の検査も同時に行う設計が扱いやすいです。
サンプルコード2:継承を利用したクラスの拡張
継承を使うと、共通する属性を親クラスへ置き、子クラスには固有の情報だけを追加できます。次の例ではAnimalが名前と年齢を持ち、Dogが犬種と鳴く処理を追加するのが基本です。
結果: 期待される出力は「名前: タロウ」「年齢: 3」「犬種: シバイヌ」「タロウが吠える」です。
この実装では、superで親クラスのコンストラクタへ共通情報を渡しています。ただし、親子関係が自然でない場合にextendsを使うと変更に弱くなるため、「DogはAnimalです」と言える関係か確認するとよいでしょう。
サンプルコード3:インターフェイスの利用
インターフェイスは、実装クラスが持つべき操作を契約として表します。クラス階層を共有しない対象でも、同じinterfaceを実装すれば、呼び出し側は同じ型として扱えますが、覚えておくと役立つでしょう。
結果: 期待される出力は「道路を走行します」と「水上を進行します」です。
この形では、AutomobileとShipに親子関係はありません。一方、どちらもVehicleActionとしてmoveを持つため、利用側は配列やリストにまとめて処理できます。
サンプルコード4:例外処理の実装
例外処理は、通常の処理では扱えない異常状態を別経路で処理する仕組みです。Javaではtry、catch、finally、throw、throwsを使って、失敗の扱いをコード上に明示します。
結果: 期待される出力は「エラー: 0での除算は行えません」です。
この例では、divide内の除算でArithmeticExceptionが発生し、catch側の処理に移ります。初心者がつまずきやすいのは、例外をすべてExceptionで受けて原因を隠してしまう点で、想定できる例外型を絞るほうが原因を追いやすくなります。
Javaプログラミングの応用例
Javaのオブジェクト指向は、コンソールアプリだけでなく、Webアプリケーション、Androidアプリケーション、APIサーバー、バッチ処理にもつながりますし、ここを基本と考えるとよいでしょう。そのため、基礎コードで扱ったクラス設計は、画面やデータベースと接続する段階でも再利用されますし、ここを基本と考えるとよいでしょう。
ウェブアプリケーションの開発
JavaのWebアプリケーションでは、HTTPリクエストを受け取り、入力値を検証し、ドメイン処理を呼び、HTMLやJSONを返す流れが一般的です。Spring Bootを使う構成では、@SpringBootApplication、@RestController、@GetMappingなどのアノテーションで起動設定やルーティングを表します。
具体的には、画面やAPIに近い層をcontroller、業務処理をservice、データアクセスをrepositoryへ分けますし、ここがポイントです。この分割により、HTTPの都合と業務ルールが混ざりにくくなり、テスト対象も切り出しやすくなります。
Javaの例外処理や文字列処理を深める場合は、Javaエスケープ処理も関連すると整理できます。一方、複数件の結果を返すAPIでは、Java List型の使い方を理解していると、戻り値の設計が読みやすくなるのが目安です。
Androidアプリケーションの開発
Android開発ではKotlinが広く使われますが、Javaで書かれた既存コードやライブラリも多く残っています。そのため、Activity、Fragment、ViewModelなどの構造を読むときにも、クラスとオブジェクトの理解が役立ちます。
Androidアプリでは、画面の状態、ユーザー操作、ネットワーク通信、保存データが互いに関係するのがポイントです。こうした要素をすべて画面クラスへ詰め込むと変更に弱くなるため、表示、状態管理、データ取得の責務を分ける設計が扱いやすいです。
その設計では、インターフェイスを使ってデータ取得元を差し替えられるようにすると、テスト用の実装を作りやすくなると理解できます。Javaのinterfaceとポリモーフィズムは、モバイル開発でも画面の複雑さを抑える道具になります。
注意点と対処法
Javaの学習でよく起きる問題は、コンパイルエラー、実行時例外、設計の肥大化に分けられますが、これは押さえたい点です。その中でもNullPointerExceptionは、オブジェクト指向の初期段階で遭遇しやすい例外です。
Javaのオブジェクト指向プログラムにおける一般的なエラーとその解決法
nullは参照先がない状態を表します。つまり、変数だけを用意して実体を代入していない状態でメソッドを呼ぶと、NullPointerExceptionが発生すると覚えるとよいでしょう。
結果: 期待される出力ではなく、NullPointerExceptionが発生する可能性があるのが一般的です。
この問題は、使う前にnew Person()で実体を作ることで解消できます。ただし、毎回null判定を足すだけでは根本的な設計が改善しない場合もあるため、生成時点で必要な値をそろえる方針が現実的です。
結果: 期待される出力は「John」です。
これに関連して、値が存在しない可能性を型で表したい場合はOptionalが候補になります。一方、Optionalをフィールドや引数に広く使いすぎると読みづらくなるため、戻り値で「ないかもしれない」を表す場面に絞る考え方が一般的です。
最適なコーディングスタイル
読みやすいJavaコードでは、名前から役割が分かりますし、これが一つの目安です。クラス名はUpperCamelCase、変数名とメソッド名はlowerCamelCase、定数はUPPER_SNAKE_CASEにするのが広く使われる慣習です。
インデントはプロジェクトで統一し、メソッドは一度に複数の責務を持たせすぎないようにすると考えられます。そのため、入力チェック、計算、出力、永続化を一つのメソッドへ詰め込むより、意味のある単位へ分けるほうが変更に追従しやすくなります。
コメントは、コードを日本語に置き換えるためではなく、判断理由や注意点を残すために使いるのが現実的です。たとえば「なぜこの条件で例外にするのか」「なぜこの順序で処理するのか」を書くと、将来の修正時に意図を失いにくくなります。
カスタマイズと拡張の方法
基礎的なクラス設計が分かると、ライブラリ、フレームワーク、デザインパターンを使った拡張へ進めますし、ここがポイントです。その段階では、何を自作し、何を既存の部品へ任せるかを切り分ける判断が必要になると整理できます。
ライブラリとフレームワークの利用
ライブラリは、特定の処理を呼び出すための部品群です。一方、フレームワークはアプリケーション全体の流れを提供し、その流れの中へ開発者のコードを差し込む構造を持ちます。
たとえばApache Commons LangのStringUtils.isBlankを使うと、null、空文字、空白だけの文字列をまとめて判定できると言えるでしょう。依存関係を追加する場合は、pom.xmlやbuild.gradleへバージョンを明記すると理解できます。
結果: 期待される出力は「空白判定: true」です。
この例は、外部ライブラリがクラスパスに入っている前提で動きます。依存関係がない環境ではコンパイルできないため、学習時は標準ライブラリだけの例と外部ライブラリの例を分けて扱うと混乱しにくいです。
Spring Bootでは、起動クラスへ@SpringBootApplicationを付け、SpringApplication.runでアプリケーションを開始します。アノテーションの理解を深める場合は、Javaアノテーションの解説も合わせて読むと関連が見えると覚えるとよいでしょう。
結果: 期待される動作は、Spring Bootアプリケーションの起動処理が開始されることです。
デザインパターンの活用
デザインパターンは、よく出る設計課題への典型的な解き方です。シングルトン、ファクトリ、ストラテジ、テンプレートメソッドなどがありますが、名前を覚えるだけではなく、どの依存関係を減らすのかを見極める必要があります。
シングルトンは、アプリケーション内でインスタンスを一つに制限したいときに使われます。ただし、共有状態が増えるとテストが難しくなるため、設定値やステートレスなサービスなど、用途を絞るほうが扱いやすいです。
結果: 期待される出力は「single instance」です。
この実装では、static finalでインスタンスを先に生成し、private constructorで外部からの生成を防いでいます。一方、DIコンテナを使うSpringアプリケーションでは、フレームワーク側がインスタンス管理を担うため、自前のシングルトンが不要な場面も多いです。
日付判定のような小さなロジックでも、責務を分ける考え方は同じです。たとえば条件分岐の練習には、Javaでうるう年を判定する実装が、分岐とメソッド分割を確認する材料になります。
まとめ
Javaのオブジェクト指向は、classで概念を作り、objectで実体化し、methodで振る舞いを閉じ込める考え方から始まりますが、覚えておくと役立つでしょう。その理解が進むと、継承、インターフェイス、例外処理、ライブラリ利用、フレームワーク設計まで一つの流れとして読めるのが基本です。
特に押さえたいのは、再利用のために何でも継承するのではなく、責務の境界を見てextends、implements、委譲を選ぶ点です。その判断ができると、機能追加時に既存コードを壊しにくい設計へ近づきます。
これから学習を進める場合は、小さなクラスを作って値と処理をまとめ、例外やテストまで含めて動作を考えるとよいでしょう。Javaの文法は広いものの、中心にある設計原則を押さえれば、WebアプリケーションやAndroid開発にも知識を展開できると考えられます。
関連記事
- Java List型完全ガイド!初心者でもマスターできる7つのステップ
- Javaアノテーションの12選!初心者から上級者まで徹底ガイド
- Javaでうるう年を判定!初心者でも分かる9ステップ解説
- Javaエスケープ処理の10ステップマスターガイド
- Javaでマスターする!オーバーライドのたった7つのステップ
※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。


