プログラミングマガジン

プログラミングを中心にIT技術をできるだけわかりやすくまとめます。

  • ホーム
  • Java
  • 【Java】オブジェクト指向:継承の問題点を解決する「抽象クラス」、「インターフェース」
 
 
     
  • サーバー言語  
    • Python
    • Ruby
    • PHP
    • SQL
  •  
  • インフラ  
       
    • AWS
    •  
    • 基本
    • Git
  • Web
       
    • Web開発
    • JavaScript
    • Vue.js
    • React
  •  
  • 設計  
       
    • 実装設計
    • DB設計
  • 問い合わせ
  

【Java】オブジェクト指向:継承の問題点を解決する「抽象クラス」、「インターフェース」

05.04

  • miyabisan2
  • コメントを書く

この記事は3分で読めます

通常の継承であれば、継承元のクラスにあるメソッドを、子クラスでどんどんオーバーライドしていくことにより、具体化していく形になりました。

継承については、下記の記事でも解説しております。

【Java】オブジェクト指向:継承の考え方や注意点

ただ、普通に継承を使っていくには、いくつか問題点が発生してきます。

結論:継承を使った方が良い場合と使わない方が良い場合

「a is b」というように親と子が全く同じ場合のみ使うのが良いでしょう。(例:雑種は犬ですなど)

「似てるから継承させる」と言う単純な理由では使わない方が良いです。(例:製品Aは製品Bです。など)

継承の際の問題点

オーバーライドをし忘れて、「何も起きない」メソッドだけができてしまう。

親クラスのメソッドに定義されているのに、子クラスでオーバーライドし忘れる問題です。

実際に、そのクラスを使うメイン処理で、親クラスにあるメソッドを呼べるので使おうとしたら、何も起きないということが起こりえそうです。

本当に何もしないメソッドとの区別がつかない。

「何をするのか子クラスで具体化してもらう」メソッドなのか、それとも「本当に何もしないメソッド」なのかの区別がつかないです。

意図せずnewされる可能性がある。

「継承元クラス」は、newされるためのものではありません。基本的には、具体化した子クラスをメイン処理ではnewさせる必要があります。

ただ、そのクラスについて何も知らない開発者であれば、意図せずnewしてしまう可能性があります。

スーパークラスを読まないとサブクラスの内容が理解できない。

いちいちソースが別れていると可読性が落ちてしまいます。継承されているとソースジャンプもしずらいですし。

子クラスでは使わないメソッドなども入りうる可能性がある。

「親クラスでは使ったとしても、子クラスでは必要ない」というケースは往々にして起こりうると思います。開発者にもその判断をさせられることになって強いまいます。親クラスは親クラスの事情でどんどんメソッドは今後増えていくことになりますし、その度に子クラスはその親クラスの必要ないメソッドが自動で追加されてってしまいます。(親クラスは子クラスのことなんて知らないですし)

もし、使わないメソッドなどが親に追加された場合はコードヒントなどで使わないメソッドが増えてしまいますしあまりよい状態ではないです。

ただ、注意点としては子クラスでしか使わないメソッドを追加していくことも「リスコフの置換原則」的にはNGになるので子クラスで独自拡張してしまうのも基本的には避けた方が良いでしょう。(ある特定の場合を除いて)

抽象クラス、抽象メソッドを使う。

上記問題を解決するために「抽象クラス、抽象メソッド」を使いましょう。

構文

1
アクセス修飾子 abstract 戻り値 メソッド名(引数);

「abstract」は、抽象という意味で、詳細未定という意味を示します。

サンプル

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public abstract class People {
 
String name; //名前
int weight;  //体重
String pc;//パソコン
 
People(String name,int weight){
this.name = name;
this.weight = weight;
}
 
//自己紹介
abstract void selfIntroduction();
 
}

Javaのルールとして、「abstract付」の抽象メソッドを一つでも含むクラスは、abstractをつけた抽象クラスとして宣言する必要があります。

1
2
3
4
5
6
7
8
9
10
11
12
public class Japanese extends People {
 
Japanese(String name,int weight){
super(name,weight);
}
 
void selfIntroduction() {
System.out.println(name + "さんは日本人です。");
System.out.println("体重は、"+ weight + "kgです。");
}
 
}

結果

親の抽象クラスをnew使用としてもnewできません。

親クラスの抽象メソッドを実装(オーバーライド)しないとエラーになります。

親クラスの抽象メソッドである「selfIntroduction」を子クラスでオーバーライドしていないため、コンパイルエラーになっています。

インターフェイスとは?

「特に抽象度が高い要素を持つクラスの仲間」のこと。(あくまで、クラスと似たようなもので、クラスではないです。)

インターフェイスの特徴

  • 全てのメソッドが抽象メソッド
  • 基本的にフィールドは一つも持たない。

※通常のフィールドは持たないですが、「public static final」だけは宣言が許されます。また、「public static finalを付いていないフィールド」を用意しても自動的に付きます。

普通の「抽象クラス」と異なり、なぜ特別扱いされるか?(「インターフェイス」という独立した文法名になっているか。)

インターフェイスは、内部実装を一切しないので特別に「多重継承」が許されているため。

(普通のクラスだと、多重継承を許してしまうと、子クラスでどのように実装するか混乱してしまいますからね。)

抽象クラスとの使い分け

違いはほとんどありません。

使い分けとしては、インターフェースは全てのメソッドを抽象化していますが、抽象クラスは一部のメソッドのオーバーライドを強制しないくらいしかないです。なので、全てのメソッドを抽象化できるようであれば、インターフェースを使いましょう。

構文

インターフェース

1
2
3
アクセス修飾子 interface インターフェイス名 {
 …
}

インターフェースを実装するクラス

1
2
3
アクセス修飾子 class クラス名 implements インターフェイス名{
 …
}

サンプル

インターフェイス

1
2
3
4
5
6
public interface People {
 
//自己紹介
abstract void selfIntroduction();
 
}

なお、インターフェイスで定義された「抽象メソッド」は、自動的に「public」かつ「abstract」になります。

実装クラス

1
2
3
4
5
6
7
public class Japanese implements People {
 
public void selfIntroduction() {
System.out.println("Hello World");
}
 
}

実装クラスでは、「抽象メソッド」をオーバーライドしますが、必ずpublicになります。

実装クラスの命名規則について

インターフェイスを実装したクラスの末尾には、「インターフェイスをimplementsしているクラス」という意味で「Impl」と付けることがたまの慣例になっています。

付けることで、どのインターフェイスを実装しているかわかるという意味合いもあったりします。

ただ、ちゃんとした本格的なプログラムの場合は、インターフェイスから、独立した意味のあるクラス名をつける方が良い場合が多いので、この慣例に従うことはあまり多くありません。

インターフェースと抽象クラスの使い分け

ほとんどありませんが、一部処理を共通化したい場合などには抽象クラスは使えます。子クラスに共通処理があるかどうかを基準にして使い分けるのが良いでしょう。

使い分けとしては、インターフェースは全てのメソッドを抽象化していますが、抽象クラスは一部のメソッドのオーバーライドを強制しないくらいしかないです。なので、全てのメソッドを抽象化できるようであれば、インターフェースを使いましょう。

スポンサーリンク
  • 2018 05.04
  • miyabisan2
  • コメントを書く
  • Java
  • Tweets Twitter
  • このエントリーをはてなブックマークに追加
  • LINEで送る

関連記事

  1. 2018 05.05

    【Java】ソフトウェアのライセンスについて

  2. 2018 05.03

    【Java】関数オブジェクト(Java8以降)

  3. 2018 05.05

    【Maven】pom.xmlの基本について

  4. 2018 06.15

    【Struts】「1系」と「2系」の違い、動作の仕組み、struts.xmlの書き方

  5. 2018 05.04

    【Maven】プロジェクトの作成方法

  6. 2018 06.19

    【Struts】EclipseにStrutsをインストールし、「Hello World!」を実行してみる。

  • コメント ( 0 )
  • トラックバック ( 0 )
  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

返信をキャンセルする。

【Webセキュリティ】ハッシュ関数(digest)、実…

【オブジェクト指向】多様性(ポリモーフィズム)のメリッ…

RETURN TOP

著者プロフィール

エンジニア歴10年で過去に業務系、Webデザイン、インフラ系なども経験あります。現在はWeb系でフロントエンド開発中心です。

詳細なプロフィールはこちら

スポンサーリンク

カテゴリー

  • Android
  • AngularJS
  • API
  • AWS
  • C++
  • CSS
  • cursor
  • C言語
  • DDD
  • DevOps
  • Django
  • Docker
  • Figma
  • Git
  • GitLab
  • GraphQL
  • gRPC
  • Hasura
  • Java
  • JavaScript
  • Kubernetes
  • Laravel
  • linux
  • MySQL
  • Next.js
  • nginx
  • Node.js
  • NoSQL
  • Nuxt.js
  • Oracle
  • PHP
  • Python
  • React
  • Redux
  • Rspec
  • Ruby
  • Ruby on Rails
  • Sass
  • Spring Framework
  • SQL
  • TypeScript
  • Unity
  • Vue.js
  • Webサービス開発
  • Webデザイン
  • Web技術
  • インフラ
  • オブジェクト指向
  • システム開発
  • セキュリティ
  • その他
  • データベース
  • デザインパターン
  • テスト
  • ネットワーク
  • プログラミング全般
  • マイクロサービス
  • マイクロソフト系技術
  • マルチメディア
  • リファクタリング
  • 副業
  • 未分類
  • 業務知識
  • 生成AI
  • 設計
  • 関数型言語
RETURN TOP

Copyright ©  プログラミングマガジン | プライバシーポリシー