質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Q&A

解決済

5回答

16727閲覧

[Java]オーバーライドの利点

ARADDIO

総合スコア160

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

0グッド

4クリップ

投稿2014/12/05 15:21

お世話になります。
Javaのオーバーライドについて質問です。

オーバーライドの利点は、
継承により効率的にスーパークラスの機能を流用しつつ、
必要に応じてサブクラスでその機能を変更することができることだと

Web、書籍等には書いてありますが、これは実行クラスがスーパークラスとサブクラスの機能を順番に呼び出した場合と何が違うのでしょうか。

単純に、実行クラスのコーディングの可読性に優れるという理解でいいのでしょうか。

とんちんかんな質問をしてしまっているかもしれませんが
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ベストアンサー

お邪魔します。

おそらく質問者さんがわからなくなっていらっしゃることは、javaのオブジェクト指向という思想の部分ですね。設計思想というか、コンセプトというか、考え方というか、定石というか。
ポリモーフィズムとカプセル化について学ばれるとよいと思います。

オブジェクト指向においては、「変更に対して開かれており、修正に対しては閉じている」状態を目指すのがよいといわれています。要するに機能の追加や変更は容易でいくらでも付け足すことができ、逆に不具合などによって修正を行う部分は極小(可能な限り1箇所にとどまる)であるべきだ、という考えですね。
そういった思想的背景から、スーパークラスとサブクラスに分けるような機構が考えだされて、処理分割を行うようになりました。(歴史的経緯が正しいかどうかはおいておいて、そうだと思ってみてください。嘘も方便のつもりで書いています。)

よくある感じの説明をすると、人類クラスをスーパーにして、Aさん、Bさんサブクラスを作る場合、人類ができること(メソッド、話すとか歩くとか)の一般的な部分を人類クラスに記述し、AさんBさん固有の動作をAさんBさんクラスにオーバーライドして記述しておけばAさんの動作を変えたい場合にAさんクラスのみを修正すればよく、人類全体に影響が及ばない、ということになります。

また、クラスを使用する側の処理から見ると、より汎用的な型(Abstractやsuper,Interface)に対してプログラミングをしておけば、サブクラスの細かい仕様変更に際して修正を施す必要がなくなります。

同じ処理をいかに1箇所にとどめるか、いかに変更や修正に際して少ない箇所の修正で済むように作るか、という観点で見ると、わかりやすいのではないでしょうか。

投稿2014/12/07 09:58

ShinpeiYamamoto

総合スコア540

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ARADDIO

2014/12/08 01:50

ご回答ありがとうございます。 修正が発生したとき、影響範囲を小さくできるというメリットがあるということですね。 しかしこれだけでは >実行クラスがスーパークラスとサブクラスの機能を順番に呼び出した場合 と同じなように思えるのですが、これはオーバーライドがカプセル化の設計思想にも即している思想なので推奨されているという理解でよいでしょうか。 それともう一つ、 >AさんBさん固有の動作をAさんBさんクラスにオーバーライドして記述しておけばAさんの動作を変えたい場合にAさんクラスのみを修正すればよく、人類全体に影響が及ばない、ということになります。 挙げていただいた例ですが、逆に人類クラスに変更があった場合はAさん、Bさん...すべてに影響があるということになりますよね。 たいていは親が変わるのだから子も変わってほしい場合が多いと思うのですが、親の影響を受けるのが問題だと思われる場合は、委譲で実装することになるのでしょうか。
ShinpeiYamamoto

2014/12/13 08:27

まず第一に、すべてのパターンの設計変更に対応できる方法はありませんから、経験則としてよくある変更で少ない修正箇所・影響範囲で済む、と考えられているということが前提ですが、 >>実行クラスがスーパークラスとサブクラスの機能を順番に呼び出した場合 >と同じなように思えるのですが、これはオーバーライドがカプセル化の設計思想にも即し>ている思想なので推奨されているという理解でよいでしょうか。 サブクラスの機能を呼び出す際のインターフェース変更はこの限りではありませんよね。 リファクタリングによる名称変更や引数の変更などを想定しています。 >挙げていただいた例ですが、逆に人類クラスに変更があった場合はAさん、Bさん...す>べてに影響があるということになりますよね。 >たいていは親が変わるのだから子も変わってほしい場合が多いと思うのですが、親の影>響を受けるのが問題だと思われる場合は、委譲で実装することになるのでしょうか。 うまく処理分割を実施していれば、変更の内容や規模にもよりますが、基本的には親だけの変更で済みます。 処理分割があまりよく考えられていない場合、言い換えると親クラスと子クラスの結合度が高い実装の場合、親クラスを変更するために子クラスを変更しなくてはならないとか、逆に子クラスを変更するために親クラスを変更しなければならないとかいった事態に陥りますが、それは設計に失敗しています。 それから、おっしゃるように継承より委譲、ですね。その方がうまくいくことが多いなあと感じます。本当ならひとつの存在(同じドメイン)の存在を無理に親子に分けてしまって、常に2つセットで修正しないといけない、というような何をやっているのかよくわからない事態は避けるべきです。 どうクラスを分けるか、がほとんどすべてだと思います。
guest

0

スーパークラス型の変数にサブクラスのインスタンスを代入し、スーパークラスのメソッド(サブクラスでオーバーライド)を呼び出すと、(スーパークラスではなく)サブクラスのメソッドが実行されます。

スーパークラスやスーパークラスを利用するクラス(サブクラスではなく、java.util.List<?>など)は、サブクラスの実装に影響されることなく、リリース後の機能強化などが可能です。
つまり、スーパークラスを主体とした利用時にメリットがあるという理解です。

例えばJDBCは、Javaのリリース当時に現在のMongoDBなどの出現は当然予想していませんが、今現在動いているのはこの恩恵です。
コネクションプーリングなどの機能強化も、まずJDBC側にメソッドを追加しリリースします。その後サブクラス(DBベンダー)がそのメソッドを実装したものをリリースすれば、利用者側でコネクションプーリングが使えるようになります。
一方、そもそもコネクションプーリング機能がないDBはいつまでも実装しないわけです。

投稿2014/12/06 01:06

jcs502ulf

総合スコア307

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ご質問の

オーバーライドの利点は、
継承により効率的にスーパークラスの機能を流用しつつ、
必要に応じてサブクラスでその機能を変更することができること

についてはサブクラスのみ生成した前提の説明になります。

オーバライドはスーパークラスのメソッド上書きとなるので、サブクラスにおいてスーパークラスのメソッドは封じられます。ですが、サブクラスのメソッドでsuper識別子を使えばスーパークラスのメソッドを呼び出せるのです。

lang

1class car{ 2 public void accel(){ 3 System.out.println("エンジン駆動"); 4 } 5} 6 7class hibrydCar extends car{ 8 public void accel(){ 9 super.accel(); 10  System.out.println("モーター駆動"); 11 } 12}

オーバライドしたメソッド内でスーパークラスのメソッドを呼びコードを加えることが「効率的にスーパークラスの機能を流用しつつ、必要に応じてサブクラスでその機能を変更することができる」に掛かっていると思います。

参考サイト

スーパークラスとサブクラスを生成してそれぞれでメソッドを呼べば、同じ結果となるケースもありますがそれはまた別の議論になるかと思います。(勘違いでしたら済みません)

投稿2014/12/05 16:38

BlueMoon

総合スコア1339

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ARADDIO

2014/12/08 01:57

ご回答ありがとうございます。 >何がメリットかというと、サブクラスがのメソッドが適切にスーパークラスのオーバーライドを実装していれば、実行クラスのコーダーはサブクラスの仕様を理解するだけで良いという点があります。スーパークラスの仕様を調べてメソッドまで呼ぶ手間が省けます。サブクラスがプロジェクト内で再利用される場合、また他の実行クラスに流用される場合などはこうした設計であればサブクラスを便利に利用できます。 これはカプセル化の思想に即していることでしょうか? しかし実行クラスのコーダーがサブクラスの仕様のみを理解しておけばよいというのは、 >実行クラスがスーパークラスとサブクラスの機能を順番に呼び出した場合 も同じなように想像するのですが、どう違うのでしょうか。  #理解が違っていたらご指摘頂けますとうれしく思います。
BlueMoon

2014/12/08 03:58

>実行クラスがスーパークラスとサブクラスの機能を順番に呼び出した場合も同じなように想像するのですが、どう違うのでしょうか。 プログラムの実行結果としては同じです。オーバライドを利用するメリットについて回答に追記しました。
BlueMoon

2014/12/08 12:04

オーバーライドとご質問の内容を勘違いしていることに気づきました。訂正も難しいので回答の先頭に記載いたします。
guest

0

これは実行クラスがスーパークラスとサブクラスの機能を順番に呼び出した場合と何が違うのでしょうか。

そもそも,これらを「順番に」呼び出すとは限りません.場合によっては,内部的に全く違う処理を行うことがあります.

例えば,Javaの原始クラスjava.lang.ObjectクラスにはtoString()メソッドや equals(Object)メソッドが有ります.
前者はオブジェクトの文字列表現を表し,後者は引数に取ったオブジェクトと比較するメソッドです.
そのまま使うと,toString()は「クラス名@ハッシュコード」という文字列を返し,
equals(Object)は引数が自分自身(と同じ参照位置)である場合のみtrue,それ以外はfalseを返します.

そして,これらのメソッドは他のメソッドで使われます.System.out.println(Object)では引数となったオブジェクトのtoString()が呼ばれ,その結果を出力します.equals(Object)はListなどで,対象のオブジェクトと同じものがListに入っているかの判定などに使われます.

この時,元の仕様そのままでは都合が悪いことがあるでしょう.例えばオブジェクトの中身を表示したいのにハッシュコードが表示されたところで意味がありませんし,オブジェクトの中身の比較をしたいのに自分自身としか等しくならないequals(Object)なんて役に立ちません.

そこで,オーバーライドの出番です.toString()でオブジェクトの中身を文字列化したものを返したり,
equals(Object)では中身が完全一致した場合にtrueを返したりという機能を実装したりします.
オーバーライドしたクラスのオブジェクトをSystem.out.println(Object)に渡せば,オブジェクトの中身を文字として出力できますし,比較もオブジェクトの中身を比較するのでより直感的になります.

こうすることで,スーパークラスであるObjectからの操作記述はそのままに,サブクラスである独自のクラスで独自の操作ができるようになります.
このように,スーパークラスのメソッドを使う場面で,サブクラスでメソッドの操作を変更できるのです.

もしオーバーライドしないのなら,自作クラスで何らかの文字列を返すメソッド(仮にgetString()とします)を作り,System.out.println(myObject.getString())と書かなければいけなくなったり,
List内に目的の中身を持つオブジェクトが入っているか調べる際もListのメソッドは使えず,
自分でループ処理を書いてオブジェクトの中身を調べるコードを書かなければならないでしょう.

投稿2015/03/09 15:16

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

実行クラスがスーパークラスとサブクラスの機能を順番に呼び出した場合と何が違うのでしょうか。

オーバーライドしないとうまくいかず、上記のような実行クラス側での呼び出しができない例を挙げてみました。

lang

1abstract class DataWriter { // いろいろなデータを出力するベースクラス 2 abstract void writeByte(int byte); 3 void writeInt(int i) { ... } // writeByteを用いて実装されている 4 void writeDouble(double d) { ... } // writeByteを用いて実装されている 5 ... // 他にもwriteByteを用いて実装されている便利メソッドがたくさんある 6} 7 8class StreamDataWriter { // ストリームへデータを出力するクラス 9 OutputStream os; 10 StreamDataWriter(OutputStream os) { this.os = os; } 11 @Override void writeByte(int byte) { os.write(byte); } 12 // 他のメソッドはスーパークラスの実装のままでよいのでこれ以上は何も定義しなくてよい 13} 14 15class BufferDataWriter { // バッファへデータを出力するクラス 16 DataBuffer<Byte> buffer; 17 BufferDataWriter(DataBuffer<Byte> buffer) { this.buffer = buffer; } 18 @Override void writeByte(int byte) { buffer.write(byte); } 19 // 他のメソッドはスーパークラスの実装のままでよいのでこれ以上は何も定義しなくてよい 20}

単なる例のためいまいちなクラスとなっていますが・・・
サブクラスであるStreamDataWriterとBufferDataWriterは出力する先が異なるだけです。お分かりと思いますがスーパークラスはバイトを出力するという機能だけをサブクラスがオーバーライドしてくれれば他のメソッドは自動的にうまく動くように意図して定義されています。
さて、このようなサブクラスに対して「実行クラスがスーパークラスとサブクラスの機能を順番に呼び出す...」というような方法ではwriteByte以外のメソッド呼び出しを記述しようがありません。説明が下手なのでみなさんのような一般性のある説明のしかたができないのですが、こんな例でも参考になるかもと思い記してみました。
いかがでしょうか。

投稿2014/12/11 11:03

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問