プログラミングをチームで効率よく開発するためには、担当領域を決めたり、似たようなコードが作らないようにするなどの工夫が必要となります。
プログラムを役割や機能に応じて分割することをモジュール分割と言ったりしますが、その際に必要となる概念がクラスです。
適切なクラス分割を行うことで、無駄がなくて読みやすく、メンテナンスのしやすいプログラムにすることができます。
プログラミング初心者にとっては、理解が難しい分野ではありますが、チームで開発するプログラマとなるためには必須の知識となります。
本記事では、Javaのクラスと継承についてまとめます。
プログラミング初心者の方の学習や、忘れてしまった方の復習として、参考にしていただければ幸いです。
記載しているプログラムは、Java11を使って動作確認をしています。
Javaのクラスと継承
Javaのクラスと継承について、以下の内容を採り上げます。
- クラスの定義方法
- コンストラクタ
- インスタンス化
- インスタンスメソッド
- インスタンス変数
- 静的メソッド
- 静的変数
- クラスの継承
- 抽象クラスと抽象メソッド
クラスの定義方法
クラスとは、動作(メソッド)や状態(プロパティ)を持つ構造(オブジェクト)です。
クラスを定義するには、class キーワードによって宣言します。
例えばPersonクラスを宣言するには、以下のように記述します。
class Person { }
コンストラクタ
コンストラクタは、そのクラスからインスタンスを作成(後述)した際に、最初に実行されるメソッドです。
通常はクラスの初期化処理を記述するために用いられます。
コンストラクタを定義するには、クラス名と同名のメソッドを定義します。
class Person { Person() { } }
インスタンス化
定義したクラスを利用するためには、インスタンス化する必要があります。
インスタンス化とは実体を作ることで、クラス定義は実体を作るための雛形やテンプレートのようなものであり、インスタンス化すると実物が作成されるというイメージです。
インスタンス化するにはnew演算子を使って作成するクラスを指定します。
以下の例では、Personクラスをインスタンス化して、personという変数に代入しています。
Person person = new Person();
インスタンスメソッド
クラスにおけるメソッドの役割は、そのクラスの動作(振る舞い)を定義するものになります。
例えば、Person(人間)クラスであれば、歩く、食べる、寝るという動作がクラスとしてのメソッドになります。
Javaでは、インスタンス化して呼出す通常メソッドをインスタンスメソッドと呼びます。
class Person { Person() { } public void walk() { System.out.println("歩きます"); } public void eat() { System.out.println("食べます"); } }
上記のクラス定義をインスタンス化して実行すると、以下のようになります。
インスタンスメソッドの実行は、インスタンスを作成する必要があります。
Person person = new Person(); person.walk(); // -> 歩きます person.eat(); // -> 食べます
インスタンス変数
インスタンス自身が保持する変数をインスタンス変数と呼びます。
インスタンス変数はメソッド外で定義し、コンストラクタで設定したり、各インスタンスメソッドから操作することができます。
コンストラクタで設定
コンストラクタの引数で渡された値をインスタンス変数に代入します。
class Person { private int age; Person(int age) { this.age = age; } public void sayAge() { System.out.println(String.format("年齢は%d歳です", this.age)); } }
上記のクラス定義をインスタンス化する際に、引数にインスタンス変数に設定する値を指定します。
Person person = new Person(30); person.sayAge(); // -> 年齢は30歳です
アクセッサで設定
インスタンス変数は、外部から自由に値を書き換えることができないようにするため、可能な限りprivate修飾子を付けて宣言します。
また、外部からアクセスする手段としてアクセッサを定義し、不適切な値の設定がされないようにチェックするなどします。
class Person { private int age; public int getAge() { return this.age; } public void setAge(int age) { if (age < 0) { throw new IllegalArgumentException("年齢は0以上の値を設定してください"); } this.age = age; } }
上記のプログラムでは、ageというインスタンス変数に対してアクセッサを定義しています。
値を取得するgetAgeメソッドを getter、値を設定するsetAgeメソッドを setter と呼びます。
setterでは設定される値に不備がないかチェックします。
上記の例では、年齢が負の値になるのはおかしいため、0以上である場合のみインスタンス変数を書き換えています。
上記のクラス定義をインスタンス化して、値を設定し、取得すると以下のようになります。
Person person = new Person(30); person.setAge(20); System.out.println(person.getAge()); // -> 20
アクセッサを利用することで、例えば読み取り専用のインスタンス変数を作ったりすることなどもできるようになります。
静的メソッド
インスタンスメソッドとは異なり、インスタンス化しなくても呼び出せる静的メソッド(staticメソッド)を定義することができます。
静的メソッドを定義するには、static を付けます。
class Person { public static void sayHello() { System.out.println("Hello"); } }
静的メソッドからは、インスタンス変数にアクセス出来ない点に注意する必要があります。
上記の静的メソッド sayHello を呼出すには、インスタンス化する必要はありません。
Person.sayHello(); // -> Hello
静的変数
静的メソッドと同様に、インスタンス化しなくてもアクセスできる静的変数(static変数)を定義することができます。
静的変数を定義するには、static を付けます。
class Person { public static String CLASS_NAME = "人間"; }
静的変数は、通常定数として用いられることが多く、final修飾子とともに書き換えられない変数として定義されることが多いです。
上記の静的変数にアクセスするには、インスタンス化する必要はありません。
System.out.println(Person.CLASS_NAME); // -> 人間
クラスの継承
クラスの継承とは、あるクラスを引き継いで新たなクラスを定義することです。
引き継ぎ元のクラスを親クラス(基底クラス、スーパークラス)と呼び、引き継ぎ先のクラスを子クラス(派生クラス、サブクラス)と呼びます。
子クラスを定義するには、extends キーワードの後に親クラスを指定して、以下のように定義します。
class Child extends Person { Child(int age) { super(age); } }
子クラスは親クラスのメソッドや変数を継承しているため、そのまま呼出すことができます。
Child child = new Child(1); child.walk(); // -> 歩きます System.out.println(child.getAge()); // -> 1
親クラスが持つメソッドを同じメソッド名で処理を書き換える(オーバーライド)こともできます。
例えば、walkメソッドを以下のようにオーバーライドします。
class Child extends Person { public void walk() { System.out.println("ハイハイします"); } }
インスタンス化して、walkメソッドを呼出すと以下のようになります。
Child child = new Child(1); child.walk(); // -> ハイハイします
親クラスが持つメソッドは、super を使って呼出すことができます。
class Child extends Person { public void eat() { super.eat(); } }
インスタンス化して、子クラスのeatメソッドを呼出しても親クラスと同じ結果が得られます。
Child child = new Child(1); child.eat(); // -> 食べます
抽象クラスと抽象メソッド
Javaでは抽象クラスと抽象メソッドを定義することができます。
抽象クラスとは、new演算子によってインスタンス化することの出来ないクラスで、子クラスを作成することを前提としたクラス定義です。
抽象メソッドとは、メソッド名だけを定義し、中身の処理は継承した子クラスにて記述することを強制するメソッドのことです。
クラス内に抽象メソッドがある場合は、必ず抽象クラスである必要があります。
抽象クラスや抽象メソッドを定義するには、abstract キーワードを使って定義します。
abstract class Animal { public abstract void cry(); } class Dog extends Animal { public void cry() { System.out.println("ワン"); } }
上記のプログラムでは、Animalクラスで抽象メソッドcryを定義し、継承したクラスDogで、中身の処理を実装をしています。
インスタンス化して抽象メソッドをメソッドを呼出すと以下のようになります。
Animal animal = new Dog(); animal.cry(); // -> ワン
上記のプログラムでは、インスタンス化するクラスはDogですが、代入する変数の型はAnimalにしています。
このようにすることで、呼び出し側は実体がDogや他のCatなどのクラスに縛られず、メソッドを呼出すとそれぞれのクラスに応じた処理をしてくれるようになります。
良いプログラマになるにはクラス設計が重要
プログラマは単にプログラミングするだけではなく、設計ができることも重要です。
チームで効率よく開発を進めるには、どんなクラス設計、継承関係、クラス間連携とするのかは重要な要素です。
クラス分割をしたり、オブジェクト指向でプログラミングするのは難しいかもしれませんが、普段から目に見えるものがどんな関係があるか、どんな振る舞いを持っているのかを考えてみると良い訓練になると思います。
今回はJavaのクラスと継承についてまとめました。
以上、参考になれば幸いです。
コメント