結論:オブジェクト指向は「データと処理をひとまとめにして、現実のモノに見立てる」だけの考え方です。用語の説明を読むだけでは絶対に腑に落ちません。実際にクラスを書いて new してオブジェクトを作ってみると、その瞬間に納得できます。
なぜオブジェクト指向は「わからない」と感じるのか
「オブジェクト指向 わからない」「オブジェクト指向 難しい」で検索する人の多くは、すでに一度は説明を読んでいるはずです。「カプセル化」「継承」「ポリモーフィズム」…どれも言葉だけ聞くと抽象的で、頭の中で像を結びません。
理由ははっきりしています。オブジェクト指向は「読んで理解する」ものではなく「書いて体験する」ものだからです。文法(変数・条件分岐・ループ)は覚えれば使えますが、オブジェクト指向は「設計の考え方」なので、実際に手を動かしてクラスを定義し、そこからオブジェクトを作ってみて初めて感覚がつかめます。
このサイトの C#のOOPコース と JavaのOOPコース は、どちらもブラウザ上でそのままコードを実行できます(無料・登録不要・環境構築なし)。読むだけで終わらせず、以下の説明を読んだらすぐ実際のレッスンで手を動かしてみてください。
クラスとインスタンスの意味を、たい焼きで理解する
一番のつまずきポイントは「クラス」と「インスタンス(オブジェクト)」の違いです。結論だけ言うと次の関係です。
- クラス = たい焼きの「型」。設計図であり、それ自体は食べられない。
- インスタンス(オブジェクト) = 型から焼き上げた「実物のたい焼き」。1つの型から何個でも作れる。
コードで書くとこうなります(C#/Java共通のイメージ)。
class Dog { ... } // クラス=設計図
Dog pochi = new Dog(); // インスタンス1つ目(実体)
Dog taro = new Dog(); // インスタンス2つ目(別の実体)
pochi と taro は同じ Dog クラスから作られていますが、名前を別々にセットすれば別々に動く別のモノになります。これが「データ(名前などのフィールド)と処理(吠えるなどのメソッド)をひとまとめにして、現実のモノに見立てる」の正体です。
このたい焼きの例をそのまま動かせるのが クラスとオブジェクト(C#) と クラスとインスタンス(Java) です。どちらも「犬(Dog)クラスからポチとタロを作る」という同じ題材で、new した瞬間に2つの独立したオブジェクトができることを実際のコードで確認できます。
カプセル化がわからない人へ ― 「なぜフィールドを隠すのか」
次によくあるつまずきが「カプセル化」です。「データを隠す」と説明されても、なぜ隠す必要があるのか実感が湧きにくいところです。
答えはシンプルで、外から自由に書き換えられると、おかしな値が入ってバグの原因になるからです。例えば「年齢」フィールドが誰からでも書き換え放題だと、うっかりマイナスの年齢を入れられてしまいます。フィールドを非公開にして、専用の窓口(プロパティやgetter/setter)経由でしかアクセスできないようにすれば、そこで値のチェックができます。
この考え方は アクセス修飾子とカプセル化(C#) と、Javaでは private フィールドと getter(Java) なぜフィールドを隠すのか(Java) setter とバリデーション(Java) で、実際に不正な値をブロックするコードを書いて確認できます。「なぜ」の部分を自分の手で再現できるので、単なる用語暗記より強く記憶に残ります。
継承とポリモーフィズムがわからない人へ ― 「共通部分をまとめる」だけ
「継承」も言葉だけだと難しく感じますが、やっていることは単純です。似たクラスの共通部分を親クラスにまとめて、子クラスは差分だけ書く、それだけです。「犬」も「猫」も「動物」という共通点(名前を持つ、鳴く)があるので、「動物」クラスを作って犬・猫はそれを引き継ぎます。
「ポリモーフィズム(多態性)」は、その延長線上にあります。同じ「鳴け」という指示を送っても、犬なら「ワン」、猫なら「ニャー」と、呼び出す側は相手の種類を気にせず、相手ごとに違う振る舞いが自動で選ばれるという仕組みです。これも文章より実装を見たほうが早いです。
- C#: 継承 → ポリモーフィズム(virtual / override) → 抽象クラス → インターフェース
- Java: extends の基本 → フィールドとメソッドの継承 → オーバーライドの基本 → 動的束縛 → 親の型で受け取る(ポリモーフィズムの威力)
この順で実際にコードを動かすと、「継承→ポリモーフィズム」がひとつながりの話であることが自然にわかります。用語集で個別に覚えるより、コースを順番に進めたほうが理解が早いのはこのためです。用語の定義だけをもう一度確認したい場合は、Wikiのオブジェクト指向の項目・クラス・オブジェクト・継承も参照してください。
つまずきやすいところ ― nullなオブジェクトを触ってしまう
オブジェクト指向を書き始めてまず遭遇するのが、まだ new していないオブジェクトを使おうとしてエラーになるパターンです。C#では NullReferenceException、Javaでは NullPointerException と呼ばれ、初心者が最初にぶつかる実行時エラーの代表格です。
原因はほぼ共通していて、「オブジェクトを入れる箱(変数)を宣言しただけで、まだ new で実体を作っていない」状態でメソッドやフィールドにアクセスしてしまうことです。詳しい原因と直し方は、NullReferenceException ― null を触った(C#) と NullPointerException ― null を触った(Java) にコード例つきでまとめてあります。エラーメッセージが出て焦ったときは、まずここを確認してください。
次に読む
- C#のOOPコースを最初から見る →(クラス・カプセル化・継承・ポリモーフィズムから、ジェネリクス・デリゲート・SOLID原則までブラウザで実行しながら学べます)
- JavaのOOPコースを最初から見る →(クラスとインスタンスから、継承・インタフェース・コレクション・例外処理までブラウザで実行しながら学べます)
- Wiki「オブジェクト指向」の用語解説 →(用語だけをさっと確認したいとき)
- C#のエラー逆引き一覧 → / Javaのエラー逆引き一覧 →(実行時にエラーで詰まったとき)