今回の記事はプログラム開発に欠かせないクラス・継承・抽象クラス・インターフェイスに関して初心者でもわかるようにコードベースでまとめて紹介する記事です。Java入門者に限らずプログラミング初心者の壁である上記を分かりやすくまとめたものとなっています。クラス・継承・抽象クラス・インターフェイスの理解ができていない方やぼんやり理解している方は是非参考にしてみてください。
クラス・継承・抽象クラス・インターフェイスについて
まず、言葉の意味を解説していきます。実装を加えた解説は次の章で行なっていきます。
- クラス
- 継承
- 抽象クラス
- インターフェイス
順番に解説していきます。
クラスの説明
クラスとは「〇〇をする」という単位で区切っておく領域のようなイメージです。
namespaceというプロジェクトの塊が例えば車だとします。車をプログラムするにあたってざっくり機能を分けると下記を考える必要があります。(かなりざっくりです。)
- 走る機能
- ナビ機能
- 見た目(色など)
機能ごとにクラスを作る利点は様々です。開発のしやすさやコードの整理に加えて、仕様の整理なども絡んできます。
クラスはインスタンスを作成することでクラス内のメソッドやフィールド値を参照(使用)することができます。
上記の車ベースに続きも解説していきます。
継承の説明
継承は先ほどのクラスの話に加えて説明します。
「走る機能」を分解すると下記のように「エンジン」の動作、「ハンドル操作」に領域を分けることができます。(こちらもざっくりです。)
ハンドルここで車を思い浮かべてほしいのですが、エンジンの動作やハンドル操作に必要な情報などがないでしょうか?
例えば「車の重さ」、「タイヤの数や大きさ」などです。こういった情報を下記のように持つことは可能です。
しかしこれは冗長な構成です。定義が複数別クラスに書かれることは例えばタイヤの数が変わった時、車の重さが変わった時などに書き換え忘れやどこのフィールド値や取得関数を参照しているかの複雑化など様々な問題があります。
そのため、下記のように継承をします。
これで、クラス1-1・1-2は「タイヤの数」「車の重さ」のフィールド値、または取得メソッドを使用することができます。
インスタンスを作成せずにフィールド値、または取得メソッドを使用できます。
基本的に上記の考えが大事で、抽象クラスとインターフェイスも似ています。
抽象クラスの説明
抽象クラスはメソッドの定義のみを先にしてメソッドの中身は実装するクラスに委ねるというものです。先ほどの車の例で説明します。
あまり考えられませんがトラックなどの車のタイヤの数が可変なものを想像してください。
その場合タイヤの数などを用いたメソッドをタイヤが4個のクラスと6個のクラスでそれぞれ作成する必要があります。
大事なことは抽象クラスで定義したメソッドは必ず実装する必要があるため実装を強制することができ、記述忘れなどが起きません。
インターフェイスの説明
インターフェイスも抽象クラスと似ています。基本的に抽象クラスと同じで、空のメソッド・フィールド値を定義でき、それらの記述を強制します。
図でいうと下記で抽象クラスと同じです。
では抽象クラスとインターフェイスの違いに関してはどこなのか。
違いは下記です。
- 継承できる数の違い(抽象クラスは1つ、インターフェイスは複数できる)
- 記述方法
- 概念(抽象クラスは「他のクラスにも承継できる機能のフレームワークの作成」、インターフェースは「共通機能があることを示す定義」)
ではいよいよそれぞれの実装を行なっていきます。実装を見るとさらに分かりやすくなると思います。
クラス・継承・抽象クラス・インターフェイスを実装
まずはJavaの環境構築が必要です。環境構築は下記記事で紹介しているのでそちらを参考に行なってください。
クラスの実装
まずはSampleClassというクラスを作成し、メソッドを定義してみます。
package org.example;
public class SampleKeisyoClass {
public void printHello() {
System.out.println("Hello クラス");
}
}
「Hello World」をコンソールに出力するメソッドを含んでいます。
これをMain関数で呼び出してみましょう。
package org.example;
public class Main {
public static void main(String[] args) {
// インスタンスの作成
SampleClass sampleClass = new SampleClass();
// インスタンス化したクラスのメソッドを使用
sampleClass.printHello();
}
}
クラスのインスタンスを使ってそのクラスのメソッドを使用することができました。
では次に継承の実装に進みます。
継承の実装
まずは「SampleKeisyoClass」を作成します。
package org.example;
public class SampleKeisyoClass {
public static void printKeisyoHello() {
System.out.println("Hello 継承");
}
}
これを先ほどのMainクラスで継承してみます。
package org.example;
public class Main extends SampleKeisyoClass {
public static void main(String[] args) {
// 継承したクラスのメソッドを使用
printKeisyoHello();
}
}
「extends SampleKeisyoClass」がクラスの後ろについています。
もちろん継承したクラスのメソッドをインスタンスを作成して使用することできます。
package org.example;
public class Main extends SampleKeisyoClass {
public static void main(String[] args) {
// 継承したクラスのメソッドを使用
printKeisyoHello();
// 継承したクラスのインスタンスを作成して関数を利用する
SampleKeisyoClass sampleKeisyoClass = new SampleKeisyoClass();
sampleKeisyoClass.printKeisyoHello();
}
}
こちらは継承のためMainクラスの中で「printKeisyoHello」メソッドを定義することはできません。
抽象クラスの実装
抽象クラス使い方は上記のクラスの継承に似ています。まずは抽象クラス「SampleAbstractClass」を書いてみます。
package org.example;
public abstract class SampleAbstractClass {
public static void printAbstractHello() {
}
}
中身は空にしておきます。
これをMainクラスで使用してみましょう。
package org.example;
public class Main extends SampleAbstractClass {
public static void main(String[] args) {
// 抽象クラスの実装を使用
printAbstractHello();
// Abstractクラスのインスタンス作成
// SampleAbstractClass sampleAbstractClass = new SampleAbstractClass();
// → 抽象クラスはインスタンス作成できないのでエラー
}
// 抽象クラスの実装
public static void printAbstractHello() {
System.out.println("Hello 抽象クラス");
}
}
抽象クラスは継承した際にメソッドの作成を強要されるのでそちらにHello出力関数を定義します。
また、抽象クラスはインスタンスの作成ができないのでインスタンス作成のコードを書くとエラーになります。
抽象クラスを使用する際は継承と同じく「extends SampleAbstractClass」で継承できます。ちなみに継承できるクラスは1つのみですので複数をコンマで繋いで下記のように継承しようとするとエラーが出ます。
public class Main extends SampleAbstractClass, SampleClass {
インターフェイスの実装
インターフェイスの作り方は下記のように記述します。
package org.example;
public interface SampleInterface {
public static void printInterfaceHello() {
}
}
これをMain関数で実装してみます。
package org.example;
public class Main implements SampleInterface {
public static void main(String[] args) {
// インターフェイスの実装
printInterfaceHello();
// インターフェイスのインスタンス作成
// SampleInterface sampleInterface = new SampleInterface();
// → インターフェイスはインスタンス作成できないのでエラー
}
//インターフェイスの実装
public static void printInterfaceHello() {
System.out.println("Hello インターフェイス");
}
}
インターフェイスの実装をMain関数で行い、使用しています。こちらも抽象クラスと同様メソッドを強要します。
また、「implements SampleInterface」でインターフェイスは実装されます。こちらはクラスと違って複数つなげることができます。
もう一つ追加でインターフェイスを作成して試してみましょう。
package org.example;
public interface AdditionalInterface {
public static void printInterfaceAdditionalHello() {
}
}
package org.example;
public class Main implements SampleInterface, AdditionalInterface {
public static void main(String[] args) {
// インターフェイスの実装
printInterfaceHello();
printInterfaceAdditionalHello();
}
//インターフェイスの実装
public static void printInterfaceHello() {
System.out.println("Hello インターフェイス");
}
public static void printInterfaceAdditionalHello() {
System.out.println("Hello 追加のインターフェイス");
}
}
インターフェイスとクラスの継承・抽象クラスの実装は同時に行うことができます。
package org.example;
public class Main extends SampleAbstractClass implements SampleInterface {
public static void main(String[] args) {
// 抽象クラスの実装を使用
printAbstractHello();
// インターフェイスの実装
printInterfaceHello();
}
// 抽象クラスの実装
public static void printAbstractHello() {
System.out.println("Hello 抽象クラス");
}
//インターフェイスの実装
public static void printInterfaceHello() {
System.out.println("Hello インターフェイス");
}
}
まとめ
以上でクラス・継承・抽象クラス・インターフェイスの説明を終了します。
今回説明した部分は分かりやすく基本的な実装をしており、実際のプロジェクトで使用されている部分はもう少し複雑かもしれません。しかし、基本的には上記を押さえておけば基礎的な部分は同じなので理解が進むと思います。
間違っている部分の指摘や質問はコメントから宜しくお願い致します。
他にもJava・SpringBoot関連の記事を記載しているので是非興味あればサイト内みて行ってください。
コメント