前回は、変数・条件分岐・繰り返し・配列・メソッドなど、Javaの基本文法を振り返りました。
今回は、Javaを学ぶ上で重要なオブジェクト指向について振り返ります。
これまでの記事では、次の内容を順番に学習してきました。
それぞれを別々に覚えるのではなく、今回はそれぞれがどのようにつながっているのかを整理してみましょう。
オブジェクト指向とは、現実世界の「モノ」をイメージしてプログラムを作る考え方です。
例えば「車」であれば、次のような情報や動作を持っています。
情報(状態)
動作
このような関連する情報と動作をまとめて管理することで、プログラムを整理しやすくします。
オブジェクト指向では、クラスとオブジェクトという考え方が重要です。
例えば、Carクラスを作ってみます。
public class Car {
private String color;
public void run() {
System.out.println("車が走ります。");
}
}
このCarクラスが「設計図」です。
設計図から実際のオブジェクトを作るには、newを使用します。
Car car = new Car();
1つのクラスから、複数のオブジェクトを作ることもできます。
Car car1 = new Car();
Car car2 = new Car();
オブジェクトを作成するときに、初期値を設定したい場合があります。
そこで利用するのがコンストラクタです。
public class Car {
private String color;
public Car(String color) {
this.color = color;
}
}
オブジェクトを作るときに値を渡します。
Car car = new Car("赤");
これによって、オブジェクトを作成すると同時にcolorへ「赤」を設定できます。
コンストラクタは、オブジェクトを作成するときの初期設定を行うために利用されます。
オブジェクトが持っているデータを、外部から自由に変更できると困る場合があります。
そこで、privateを利用してデータを保護します。
private int speed;
privateにすると、クラスの外から直接変更できなくなります。
必要に応じて、getterやsetterを用意します。
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
if (speed >= 0) {
this.speed = speed;
}
}
setterを通して値を変更することで、不正な値が設定されることを防ぐこともできます。
このように、データを保護し、必要な方法でアクセスできるようにする考え方がカプセル化です。
複数のクラスに共通する機能がある場合、同じ処理を何度も書くのは大変です。
そこで利用できるのが継承です。
例えば、CarクラスをSportsCarクラスが継承するとします。
public class SportsCar extends Car {
}
extendsを使うことで、親クラスの機能を子クラスへ引き継ぐことができます。
Car
↓
SportsCar
SportsCarはCarの機能を利用しながら、独自の機能を追加できます。
public class SportsCar extends Car {
public void turbo() {
System.out.println("ターボで加速します。");
}
}
親クラスから継承したメソッドを、子クラス用の処理に変更することもできます。
これをオーバーライドと呼びます。
public void run() {
System.out.println("車が走ります。");
}
@Override
public void run() {
System.out.println("スポーツカーが高速で走ります。");
}
同じrun()というメソッドでも、SportsCarに合った処理へ変更できます。
継承とオーバーライドを利用すると、ポリモーフィズムという仕組みを活用できます。
例えば、次のコードを見てみましょう。
Car car = new SportsCar();
変数の型はCarですが、実際に作られているオブジェクトはSportsCarです。
この状態でrun()を呼び出します。
car.run();
SportsCarでrun()がオーバーライドされている場合、SportsCarのrun()が実行されます。
スポーツカーが高速で走ります。
同じメソッドを呼び出しても、実際のオブジェクトによって動作が変わる。
これがポリモーフィズムの重要なポイントです。
ここまで学んだ内容を、一度まとめてみましょう。
オブジェクト指向
↓
クラスを設計する
↓
newでオブジェクトを作る
↓
コンストラクタで初期設定
↓
カプセル化でデータを保護
↓
継承で共通する機能を引き継ぐ
↓
オーバーライドで動作を変更
↓
ポリモーフィズムで
同じ呼び出し方から異なる動作を実現
それぞれを単独の知識として覚えるのではなく、一連の流れとして考えると理解しやすくなります。
最後に、これまでの内容を組み合わせて確認してみます。
public class Car {
private String color;
public Car(String color) {
this.color = color;
}
public String getColor() {
return color;
}
public void run() {
System.out.println("車が走ります。");
}
}
public class SportsCar extends Car {
public SportsCar(String color) {
super(color);
}
@Override
public void run() {
System.out.println("スポーツカーが高速で走ります。");
}
}
public class Main {
public static void main(String[] args) {
Car car = new SportsCar("赤");
System.out.println("色:" + car.getColor());
car.run();
}
}
色:赤
スポーツカーが高速で走ります。
この短いプログラムにも、これまで学んだ内容がいくつも含まれています。
これまで別々に学習してきた内容が、実際のプログラムではこのように組み合わされています。
オブジェクト指向は、Javaを学び始めたときにつまずきやすい部分の一つです。
特に、
などは、最初からすべて理解するのが難しいかもしれません。
まずは、「どのクラスがどのクラスを継承しているのか」「実際に作られているオブジェクトは何なのか」を確認しながらコードを読むことを意識してみましょう。
ここまで、Javaの基本文法からオブジェクト指向まで学習してきました。
Javaの基礎学習では、文法を暗記することよりも、「この処理を作るには、どの仕組みを使えばよいのか」を考えられるようになることが大切です。
分からなくなったときは、それぞれの基本に戻って確認してみましょう。
これで、Javaの基本文法とオブジェクト指向の振り返りは終了です。
次回からは、これまで学んだ基礎をもとに、Javaの応用的な内容へ進んでいきます。