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

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

ただいまの
回答率

90.86%

  • Java

    12467questions

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

  • オブジェクト指向

    253questions

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

抽象クラスって何?そもそも抽象って?そんなこと起こり得るの?

解決済

回答 12

投稿

  • 評価
  • クリップ 4
  • VIEW 1,255

mr0237

score 137

JAVAを勉強している者です。説明が下手ですいませんが、オブジェクト指向の「抽象」及び「抽象クラス」って一体何なんでしょうか?

ネットや参考書みても「あいまいな及びあいまいなクラス」と書いてあるんですが、何なのかよくわかりません。

まだ勉強不足だと思いますが、「抽象」というのは、「プログラムの処理内容がまだ確定(未完成?)していない、詳細未定(未完成?)メソッド」みたいなことが書かれてありました。

さらに、「抽象クラス」というのは「フィールドと詳細未定(未完成?)メソッドが存在するクラス」みたいなことが書かれてあり、その「詳細未定(未完成?)メソッドがたくさん存在するほど抽象度(あいまい度)が高いクラス」という風に書かれていました。(説明が下手ですいません。)

そもそも「プログラムの処理内容がまだ確定(未完成?)していない、詳細未定(未完成?)」というのは、しっかりと設計していないことであり、きちんと完璧に設計すればいいと思うのですが、なぜそんなことがあり得るんですか?

それに「プログラムの処理内容がまだ確定(未完成?)していない、詳細未定(未完成?)」は多人数で開発していると起こりやすいと思いますが、一人での開発ではそんなことは起きないのでは?と思っております。

わかりやすいような例や例えで教えてくれませんか? 
できれば身近な例を挙げて教えてくれませんか? 
よろしくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • ozwk

    2017/01/08 13:57 編集

    「抽象クラス」で検索してそんな雑な説明見ないんですが、継承とかオーバーライドとか書いてません?

    キャンセル

  • mr0237

    2017/01/08 14:01

    参考書に書いてありました。その参考書とは「スッキリわかるJava入門 第2版」のP444~P490あたりに書いてありました。

    キャンセル

  • gtemacomp

    2017/01/11 15:33 編集

    「ネットや参考書を見ても」だと、どこをみてもそう書いてあるような印象になりますよ!…で、その本は初心者向けにわかりやすく書いている本なので、はじめのつかみとして「とりあえず曖昧に定義するものなんだよ」ということを書いているだけだと思います。大事なのはその前後に書かれているキャラクターの会話やサンプルコードになるので、そこを理解した上で、あとで「そっか、まだ役割だけで具体的なコードは書けないから、とりあえず曖昧に定義しておくってことだな」くらいになればいいと思います。こういった初心者向けの文章は今回のようなケースがよくあるので、今後もその認識があるといいと思います。

    キャンセル

回答 12

+9

 抽象とは?

抽象は具体の反対です。
例として一つ、りんごの木を思い浮かべてみましょう。
その思い浮かべたりんごの木は、中央に太い幹があり、上に丸くてふさふさな緑があり、枝が2~3本生えててりんごがぶら下がっては居ませんか?

それってちゃんと具体的にイメージ出来てますか?
幹だって日光や水、肥料次第で千差万別で同じ物は一つもありません。
枝葉の細部なんて1本たりとも同じ物は存在しません。
そして何より、今は冬なんでりんごがぶら下がっているわけがありません。

ですが、私達は子供にりんごの木を説明する時に、
デフォルメ化された上記のりんごの木を描いて説明します。

りんごに関して詳しい農家や研究科同士が具体的なものについて議論する場合は最初から具体的で良いでしょうが、
私達のような畑違いの人が普段の会話に用いられるものはまずデフォルメされた抽象的なものを使ってわかりやすく説明していきます。
その後、会話の流れや必要に応じて細部に着目していく具体化が行われます。

 プログラミングの世界での抽象とは?

内部構造は違うが見た目や目的が同じ部品を使い分ける時に威力を発揮します。

例えばA街からB街へ荷物を運ぶという仕事があったとしましょう。
以前は技術が発達していなかったので、手段として馬車を使いました。
時間が経ち、エンジンで駆動するトラックが発明されました。

A街からB街へ荷物を運んで欲しいAさんには知ったことではありません。
馬車の行者インスタンスの集荷メソッドを叩き、引数に「物・住所・賃金」を渡す箇所が、
トラックの運転手インスタンスの集荷メソッドを叩き、引数に「物と住所と賃金」を渡すように修正されるだけの話です。

そこで「A街からB街へものを運ぶ仕事の人」という共通点をまとめた抽象クラスを用意します。
馬と車は構造が違うので同じロジックは使えないので、抽象クラスでは「集荷メソッド」とその引数だけを定義しておきます。
これが設計書になり、後から馬車やトラックを実装する人は「ああ、集荷というメソッドを用意すればいいんだな」と何を作ればよいかが明確になります。

近い将来、ドローンという空飛ぶ飛行機を操作する人が登場しても、そのモジュールを使うのに既存ロジックを作り直す必要はなく、テストも簡単に通す事が出来ますね。
また、優れたエンジニアが後からジョインした場合、抽象クラスとその実装をちら見することでどういう目的で作られたのかを把握しやすくなります。
まさに会話のテクニックで使われる森と木ですね!

 実際に使われるケース

よく用いられるのはデータベースですかね?
データを読み書きしたいクラスはただただ持っているデータベースインスタンスのqueryを叩いてSQL文を送れば良い仕組みを作っておき、
MySQLに接続するモジュール、Oracleに接続するモジュール…という風にあDBの操作をまとめた抽象クラスを定義しておくと、個々のDBの実装に影響されにくいシステムを構築出来ます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+6

抽象クラスがどんなときに必要になるのか、どういう風に役に立つのか、そんなことを示すためのサンプルプログラムを作りましたので、これを用いて説明していきます。

サンプルプログラム
Gist: 抽象クラスを説明するためのRPGプログラム

さて、何かちょっとしたRPGを作ることになりました。でも、本格的なのは面倒なので「戦闘」部分だけ作ることになりました。戦闘はもちろん自動です。ユーザーに操作させるようなゲームは時代遅れですから。

ということで、早速外側から見て行きましょう。RPGクラスが大枠のメインです。BattleFieldクラスは戦闘の状態というか戦闘の場所というか、そういった感じで戦闘を管理するものです。実際の戦闘を行わせる場合、オブジェクトには最低限必要な項目があります。例えば、名前が無ければメッセージが出せませんので、名前を取得するメソッド(getName())、生きているかどうかわからなければいけませんので、生存確認するメソッド(isAlive())などが必要です。これがちゃんと実装されていれば、問題なく戦闘が行えるはずですので、それらがあることを示すためにBattlableインターフェースを作ります。

ここで重要なのはBattleFieldクラスにとってBattlableインターフェースさえあれば十分と言うことです。それぞれのメソッドがどのように実装されているのかは関係ありません。Battlableインターフェースさえ実装されていることが保証されていれば、問題なく戦闘できるでしょう。

ここまではいいですね。では、次に、実際のプレイヤーやモンスターの実装に入ります。人間(Human)にはレベルという概念があるシステムを採用しようと思います。レベルに応じて攻撃力や防御力が高くなると言うことです。対して、モンスター(Monster)にはレベルという概念が無く、攻撃力や防御力そのものを設定するとシステムを採用しようと思います。他にも人間には命を削って発動する超必殺技みたいなのもできるようにようにしたいと考えています。となると、HumanクラスとMonsterクラス、それぞれ別に作る必要があります。あとはBattlableインターフェースを両方とも実装していれば問題ないですね。

ちょっと待ってください。攻撃力関係は確かに違いますが、HPに関する考えは一緒です。どちらも最大HPが最初のHPで、ダメージによって減っていって、0になれば戦闘不能になります。このままHumanとMonsnterを別々に作ってしまったら、このHP処理が二つの箇所でそれぞれ書く必要が出てきてしまいます。これはちょっと面倒です。

ということで、なら、共通部分を書いたものを用意しよう…となって出てくるの抽象クラスであるAbstractCreatureクラスです。AbstractCreatureクラスでは、Battlableインターフェースを含んでおいて、両方に共通になる部分を実装してしまいます。ただ、攻撃力や防御力というものは、具体的にどんなものなのかが決まらないと規定できず、実装できません。そう、どうしても未確定な部分が出てきます。そのため、そのまま直接インスタンスにはできない抽象クラスとして定義する必要があります。

このAbstractCreatureクラスを継承してHumanクラスやMonsterクラスを作るととても便利だとわかります。HumanクラスやMonsterクラスで面倒なHP計算とかの処理が不要になるからです。このように、コードを共通化するために親クラスを用意することはよくあるパターンです。ですが、その親クラスで未確定な部分が出てしまう場合に、抽象クラスにすることで、未確定な部分、つまり、抽象メソッドをサブクラスでの実装に任せると言うことができます。

もう一つ重要なことがあります。抽象クラスを継承するサブクラス自体が抽象クラスで無ければ、そのクラスで抽象メソッドは必ず実装しなければなりません。これは、インターフェースと一緒です。このように、実装を強制し、実装漏れを防ぐと言うこともできます。

だいたいわかったでしょうか?実装の強制という所ではインターフェースと同じです。しかし、抽象クラスでは、他のクラスのようにフィールドや実装されたメソッドが使用できます。つまり、コードの共通部分をまとめて親クラスに書いておきたい。しかし、その親クラスには未確定部分が含まれるため、普通のクラスにできない。そんなときに使うのが抽象クラスとなります。

なお、Java8からはインターフェースでdefaultメソッドというものが定義できるようになりました。これは、実装を含むメソッドであり、インタフェースを継承する全てで使える共通のコードを書くことができます。つまり、今まで抽象クラスが担っていた、コードの共通化をインターフェースもできるようになりました。ただ、インタフェースはコンストラクタやインスタンスフィールドを持つことはできませんので、抽象クラスの機能全てがインタフェースでまかなえるようになったというわけではありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+5

確かに「あいまいなクラス」という言い方をしてはわかりにくいですね。
しかし、あいまいということは裏を返せばいろいろな形をとりえるということでもあります。

抽象クラスではなくてインタフェースですが、Listを例にとって説明したいと思います。
Listの実装型として、

  • 内部を配列として持ち、状況に応じて配列のサイズを適宜変更できるようにしたArrayList
  • それぞれの要素が、リストの中で自分の次および前の要素が何かを持っているLinkedList

などがあります。後者がリストとしてイメージしづらいかもしれませんが、{1,2,3,4,5}のようなリストがあったとして、「3」という要素が、自分の前が「2」、自分の後が「4」という情報を持っており、そういう情報をすべての要素が持っていることでリストとしての体裁を持っています。何のためにと思うかもしれませんが、こうすることで頻繁に要素を追加・削除する際に有利なのです。

ひとまず、この2つを例に挙げて説明します。

例えば、リスト内のある場所、例えば「3番目」の要素を取得したいとします。
ArrayListの場合はリストを配列で持っているため、配列にアクセスするのと同じようにarray[3]のようにして取得できます。しかしLinkedListの場合、要素の位置に番号が振られているわけではないので、配列のようにアクセスできません。じゃあどうするのかというと、先頭の要素から順番に数えながら「3番目」を探します。
このように、同じ「3番目の要素を取得する」という操作でも、内部では全く別の処理をしているため、これを完全に別クラスとして記述すると「別のもの」として扱われ、統一された手法で操作できません。

もう一つ例を挙げましょう。リストの途中に要素を挿入したいとします。例えば要素が5つ(0番~4番)あるリストに対し、「2番目に要素を挿入したい」というような場合です。
ArrayListの場合、まず2番目の場所を開ける必要があります。そのため、2番目以降の要素を1個ずつ後ろに移動させ、そのあとで要素を2番目に収めるという操作になります。
一方LinkedListの場合、「1番目の要素の次」と「2番目の要素の前」を挿入したい要素に設定し直し、挿入する要素の前後をそれぞれ(元の)1番目と2番目に設定するという形になります。
これも、リストとしてやりたいことは一緒なのに、内部の構造が違うために全く違う操作になるため、全くの別メソッドになります。この2つを統一した方法で操作できないのは直感的ではないですよね?

そこで登場するのがListインタフェースです。
先ほど挙げた2例、つまり「番号を指定した要素の取得」と「番号と要素を指定した挿入」は、Listインタフェースでそれぞれget(int),add(int,T)(※Tはリストが扱う要素の型)という、質問者の言葉を使えばあいまいなメソッドを持っています。しかし、あいまいであるが故、どのような行動でも可能なのです。

List型の変数には、ArrayListもLinkedListも代入することができます。そして、どちらが入っていようとも、要素を取得したければget(int)、要素を挿入したければadd(int,T)と、統一された方法でリストを操作することができるのです。これが、抽象クラスやインタフェースのメリットです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

 抽象クラスがある理由

抽象クラスが存在するのは「メソッドがあることを保証する」ことです。

保証というのは。。。
例えば、以下の抽象クラスはclose()できることを保証するのが目的です。

Closeable: close()できることを保証するクラス(自作クラスです)

abstract class Closeable{ // (標準のクラスではなく自作です)
    abstract void close();
}

例えば、これを継承して
MyFileクラス
MySocketクラスを作ります
(ファイルもソケットも両方ともclose()できることが保証できそうなものです)
(ソケットは通信で使うソケットを想定した名前です)

class MyFile extends Closeable { // MyFileはclose()できることを保証します 
   String filePath;
   ....

   void close(){
      /** close()を実装しないとコンパイルエラーしちゃうので **/
      /** MyFileには、close()が呼び出せることが保証されます **/
   }
}
class MySocket extends Closeable { // MySocketはclose()できることを保証します 
   long id;
   ...

   void close(){
      /** MySocketには、close()が呼び出せることが保証されます **/
   }
}

「インターフェースでもできるんじゃないの?」と思った方は下を読んでみてください。

 インターフェースでもできるんじゃないの?

上のCloseableはインターフェースでも実現可能です。
ただ、インターフェースだと実装が書けない[^1]ので、実装もしたくなったときに抽象クラスが活躍します。

「比較可能なことを保証するクラス」を抽象クラスを使って作ってみます。

Orderable: 比較可能であることを保証するクラス(自作クラスです)

abstract class Orderable{


  // [戻り値]
  // this == ordなら 0
  // this <  ordなら 負の数
  // this >  ordなら 正の数
  abstract int compare(Orderable ord);


  // lessThan()
  // graterThan()
  // isTheSame()
  // はcompareを使って実装できます

  boolean lessThan(Orderable ord){
    return compare(ord) < 0;
  }

  boolean graterThan(Orderable ord){
    return compare(ord) > 0;
  }

  boolean isTheSame(Orderable ord){ // [^2]
    return compare(ord) == 0;
  }
}

このOrderableがあれば、Javaプログラマはcompareを実装するだけで、
lessThan()graterThan()isTheSame()も使えるようになります!一つ実装するだけで、他のメソッドも使えるようになるのは便利ですよね。

Orderableの設計が問題があると思う方は、以下を御覧ください。

 [念のために] サンプルコード妥協点

念のために書いておきます。
このOrderableは設計に問題があります。

しかし、Orderableの例は「一つ実装するだけで、他のメソッドも使えるようになるのは便利ですよね。」を納得してもらう目的で作りました。抽象クラスの説明に他のJavaの技術が混じって複雑にならないようにすることを選びました。

設計の問題というのは、

クラスA、クラスBも両方共Orderablecompareをちゃんと定義したとします。

class A extends Orderable{...}
class B exteds Orderable{...} 

そのとき
abという違うクラス同士での比較ができてしまう点が問題です。
この問題を解決するには、Orderableのようなクラスを作るときはジェネリックスを使えば大丈夫です。

A a = new A();
B b = new B();
a.lessThan(b); // これが問題

 改良版Orderable

ジェネリックスを使って上記の問題を解決したOrderableです

abstract class Orderable<T>{


  // [戻り値]
  // this == ordなら 0
  // this <  ordなら 負の数
  // this >  ordなら 正の数
  abstract int compare(T ord);


  // lessThan
  // graterThan
  // isTheSame
  // はcompareを使って実装できます

  boolean lessThan(T ord){
    return compare(ord) < 0;
  }

  boolean graterThan(T ord){
    return compare(ord) > 0;
  }

  boolean isTheSame(T ord){ // [ここは気にしないで] equalsにしなかったのは、Object#equals(Object)を正しく実装できないからです
    return compare(ord) == 0;
  }
}

class MyInteger extends Orderable<MyInteger>{
  int value;
  public MyInteger(int value){
    this.value = value;
  }


  int compare(MyInteger that){ // 注意:引数の名前はthatです
    // this == thatなら0、this < thatなら負の数、this > thatなら正の数にちゃんとなります
    return this.value - that.value;
  }

}

`

使い方は

class MyInteger extends Orderable<MyInteger>{
  int value;
  public MyInteger(int value){
    this.value = value;
  }


  int compare(MyInteger that){ // 注意:引数の名前はthatです
    // this == thatなら0、this < thatなら負の数、this > thatなら正の数にちゃんとなります
    return this.value - that.value;
  }

}
MyInteger i1 = new MyInteger(10);
MyInteger i2 = new MyInteger(5);

System.out.println(i1.lessThan(i2));    // => false
System.out.println(i1.graterThan(i2));  // => true
System.out.println(i1.isTheSame(i2));   // => false

[^1]: Java 8以降からはdefaultを使ってインターフェースでも実装が書けるようになりました。しかし、Javaでは長い間、インターフェイスに実装が書けなかったのです。

[^2] equalsにしなかったのは、Object#equals(Object)を正しく実装できないと判断したからです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+1

そもそも「プログラムの処理内容がまだ確定(未完成?)していない、詳細未定(未完成?)」というのは、しっかりと設計していないことであり、きちんと完璧に設計すればいいと思うのですが、なぜそんなことがあり得るんですか? 

ここで言うところの「未確定」「未完成」というのは、コンパイラーから見た話であり、その実態は完璧に設計した結果そうなったのであります。

先端が付け替え可能なドライバーセットを想像してください。グリップだけでは何もできず、先端を付けなければ機能しませんが、その代わり、目的に応じた先端を付け替えることでいろんな種類のねじに対応させることができます。別の言い方をすると、目的に応じて先端を付け替えられるようなドライバーを設計したら、そのようなグリップになったということです。

このグリップ部分が抽象クラスと考えることができます(厳密には違うかもしれませんが考え方として)。つまり、派生させて目的に応じた機能を実装させることを前提として設計したクラスが抽象クラスです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/08 14:03

    コンパイラーから見た話ってどういうことなんでしょうか?

    キャンセル

  • 2017/01/08 14:53

    抽象クラスは実体化することができないという意味です。抽象クラスには必然的に抽象メソッドがあるわけですが、コンパイラーはそのメソッドが何をするのかが判らないのでnewできません(エラーになるはずです)。つまり、コンパイラーにとっては抽象クラスをそのままでは使うことができないということです。ですが、設計者にとっては何のために抽象クラスにしたのか、そのクラスで何ができるのか(何に使うのか)、ということは明確に判っていることです。

    キャンセル

+1

抽象クラスは、それそのものだけでなく多態性(ポリモルフィズム)を使用した時に真価が発揮されるように思えます

以下が具体的にどう役に立つのかのコード例です

抽象クラスの概念がある事で、実装クラスの中身が実装クラスごとに変化しても一括してそれらを扱えるようにできる事が分かると思います
身近な例を用いて説明しました

ファイル名:Jyuyou.java

abstract class{// 抽象クラス

    int i = 0;

    abstract void 否認();// 自分の死そのものを疑う段階

    abstract void 怒り();// 自分が死ぬことへの怒りを感じている段階

    abstract void 取り引き();// 死を免れようとあがき回る段階

    abstract void 抑うつ();// 気分が落ち込み何もできない段階

    abstract void 受容();// 死をついに受け入れた段階

    void 死の受容過程() {// 上記過程の連続再生

        System.out.println("死の受容例" + (i + 1) + "人目");
        slp();
        System.out.println("\n---" + (i + 1) + "人目:" + "死の受容の過程1~否認~---");
        slp();
        否認();
        slp();
        System.out.println("\n---" + (i + 1) + "人目:" + "死の受容の過程2~怒り~---");
        slp();
        怒り();
        slp();
        System.out.println("\n---" + (i + 1) + "人目:" + "死の受容の過程3~取り引き~---");
        slp();
        取り引き();
        slp();
        System.out.println("\n---" + (i + 1) + "人目:" + "死の受容の過程4~抑うつ~---");
        slp();
        抑うつ();
        slp();
        System.out.println("\n---" + (i + 1) + "人目:" + "死の受容の過程5~受容~---");
        slp();
        受容();
        slp();
        System.out.println("\n\n\n\n");
        slp();

    }

    void set(int o) {// 何人目か
        i = o;
    }

    void slp() {// 表示間隔
        try {
            Thread.sleep(600);
        } catch (Exception e) {
        }
    }

}

class 死を待つ人1 extends{// 抽象クラスを実装したクラス1

    void 否認() {
        System.out.println("私は癌ではありません 検査のやり直しを要求します");
    }

    void 怒り() {
        System.out.println("何で俺が死ななきゃならないんだ! 死にたくないって言ってるだろ!");
    }

    void 取り引き() {
        System.out.println("すみません 癌の特効薬があると言うのはこちらですか");
    }

    void 抑うつ() {
        System.out.println("死にたくありません 僕は死にたくないんです");
    }

    void 受容() {
        System.out.println("最近、死ぬのも悪くないって思えるようになったんです");
    }

}

class 死を待つ人2 extends{// 抽象クラスを実装したクラス2

    void 否認() {
        System.out.println("あの医者俺が死ぬなんて嘘なんでついたんだろ");
    }

    void 怒り() {
        System.out.println("やめろ・・・死ぬとかそんなの本人に言っていいと思ってるのか!");
    }

    void 取り引き() {
        System.out.println("分かりました 分かりました食事療法で少しでも生きられるんですね");
    }

    void 抑うつ() {
        System.out.println("嫌だ・・死にたくない・・・・耐えられない・・・・");
        slpl();
        for (int i = 0; i < 400; i++) {
            System.out.print("死にたくない ");
        }
        System.out.println();
    }

    void 受容() {
        System.out.println("昨日お迎えが来る夢を見たんです");
    }

    void slpl() {
        try {
            Thread.sleep(2000);
        } catch (Exception e) {
        }
    }

}

class 死を待つ人3 extends{// 抽象クラスを実装したクラス3

    void 否認() {
        System.out.println("昨日死の宣告を受ける夢を見た リアルだったが夢は夢だ そうだあれは夢だ");
    }

    void 怒り() {
        System.out.println("俺が死んだら残された皆はどうなるんだ!  そんなの認められるはずがないだろうが!");
    }

    void 取り引き() {
        System.out.println("この万病に効くエキスさえあれば・・・");
    }

    void 抑うつ() {
        for (int i = 0; i < 25; i++) {
            System.out.print("嫌だ・・・死にたくない・・・ ");
            slpl();
            System.out.print("あの頃・・・食事に気を付けてさえいれば・・・ ");
            slpl();
            System.out.print("これは夢だ・・・夢だ・・・ ");
            slpl();
        }
        System.out.println();
    }

    void 受容() {
        System.out.println("僕が死ぬことは最初から定められていた運命だったんです だからこれは仕方のない事なんです");
    }

    void slpl() {
        try {
            Thread.sleep(50);
        } catch (Exception e) {
        }
    }

}

class Jyuyou {

    public static void main(String[] args) {

        死 a[] = new 死[3];// 配列変数aに全ての実装クラスのインスタンスを一括して入れられる(多態性)

        a[0] = new 死を待つ人1();
        a[1] = new 死を待つ人2();
        a[2] = new 死を待つ人3();

        for (int i = 0; i < 3; i++) {// このfor文の中で行われる操作は
//a配列の中に入るクラス死の実装クラスをどれだけ増やしても同じで済む

            a[i].set(i);
            a[i].死の受容過程();

        }

    }

}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

マウスを例にします。

マウス売り場にはボタンが3つ以上付いていたり、トラックボールであったり、USB接続できたり、Bluetooth接続できたりと多様性がありますよね。

しかし、マウスは下記の最低限の機能を持っています。
・右クリックボタンが付いている。
・左クリックボタンが付いている。
・移動する。
・PC等に接続する。
・クリックした情報を送信する。
・移動させた情報を送信する。

このように、マウスがマウスとして成り立つための機能を抽象クラスとして定義しておくことで、新商品を作るときにこのクラスを継承し、実装することでマウスとして成り立つことになります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

抽象メソッドとは、オーバーライドされる前提のメソッドで、
抽象クラスとは、抽象メソッドを含むクラスです。

未完成なわけじゃないです。あえて詳細を決めないだけです。

オーバーライドって何?と思ったらお手持ちの参考書を戻りましょう。
そこを読む段階に達していません。

"HelloWorld"を出力するプログラムを考えます。
出力先は、標準出力や、ファイルなどが選べるとします。
このとき、

abstract class Writer{
    abstract void Write(String text);
}


こんな抽象クラスを用意して、

class HelloWorld{
    static void Greeting(Writer w){
        w.Write("HelloWorld");
    }
}

こう使えば、渡された抽象クラスの実装によって何処に出力するか切り替えられます。
例えば標準出力版は

class ConsoleWriter extends Writer{
    void Write(String text){
        System.out.println(text);
    }
}
public class Main {
    public static void main(String[] args) throws Exception {
        Writer w = new ConsoleWriter(); // 実用的にはwの中身はいろいろ選択できるようにする
        HelloWorld.Greet(w);
    }
}

ちなみにこの例だとinterfaceでいいんですが、
抽象クラス使ったほうが良いコードはコード長くなるのでこうしました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

文字通り「抽象的」なクラスです。この性質上、このインスタンスを直接作ることはできません。継承した上でサブクラスのインスタンスを作るための中間的なものです。

例えるならば、「単独では用を成さない部品」みたいなものです。(厳密に書けばis a関係なのでhas a関係を例にするのは不適切ですが気にしないでください。)

また、「サブクラスに共通して使用できること」も重要です。プログラミングの都合上、「作業後期になるまで確定しない仕様」、「出荷後に判明するバグ」といったものにも対策が必要です。これらのため、後になってからプログラムを一部だけ切り替える機能が必要となります。ここでもこの性質が有効となります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-2

参考情報:

ポケモンGO で、メタモンやその他のポケモン(かくとうとかこおりの属性ももっている)を プログラミングで class 定義していたとしたら、どうなるかを考えてみると面白いかもしれない。
ジム戦では、メタモンはメタモンとして戦うことはできない。
(でもメタモン同士を戦わせたことがあるが、そのときはメタモン同士の戦いになったけど)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-3

以下が4言語のオブジェクト指向操作のための命令一覧表です。10年前の編集なので、C#やUnityやythonなどは取り上げていません。このように各言語がオブジェクト指向プログラミングを実装しているという点では、OOPの必要性は大きいといえます。
4言語のオブジェクト指向操作のための命令一覧表(図の校正中)
各言語の癖はありますが、操作手順の大枠は共通しています。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/08 14:27 編集

    いや、Javaのオブジェクトに対してdestroy()なんてないですし…
    Threadクラスにはありますが非推奨(必ずエラーを吐き出す)ですし…

    キャンセル

  • 2017/01/08 14:38 編集

    C++のインスタンス生成もCreate()じゃないし…
    それただ単にFactoryでよく使われる名前なだけだし…
    破棄もdeleteだし…

    キャンセル

  • 2017/01/08 15:46

    不正確な情報を掲載して申し訳ありません。
    10年前の私の勉強の不十分さがここにきてさらされてしまい、お恥ずかしい限りです。
    とりあえず、画像は削除し、Webページの方も再編集していきます。
    JavaとC++以外にもお気づきのカ所がありましたらどうぞお教え下さい。

    キャンセル

-4

オブジェクトは道具の一般的な概念です。
例えば、電卓とは計算できて答を表示するものと当然のように分かっていますが、各電卓メーカーは各自が具体的な製品を製作し世に出します。つまり、抽象的な電卓はクラスにあたり、各社の製品はインスタンスにあたります。
実際に加える機能と取り除く機能を用意した電卓オブジェクトを定義します。変数はkotaeのみ、メソッドはコンストラクタも表示メソッドも省いたtasuとhikuの2つだけです。

Dentaku0.java

public     abstract class Dentaku0<T> {
    private Object kotae;
    public <T> void tasu(){};
    public <T> void hiku(){};
}


この抽象クラスの電卓は、整数用なのか実数用なのかあいまいな電卓です。
このDentaku0から整数計算用の電卓と実数計算用の電卓を派生させ、それぞれ操作します。
Dentaku_seisuu.java

public class Dentaku_seisuu<D> extends Dentaku0<D> {
      int kotae = 0;
      public int tasu(int kazu) {
        return kotae += kazu;
      }
      public int hiku(int kazu) {
        return kotae -= kazu;
      }
}


この整数用電卓を操作する見本プログラムが次のコードです。
Dentaku_seisuu_Sousa1.java

public class Dentaku_seisuu_Sousa1 {
      public static void main( String args[] ) {
          Dentaku_seisuu<Object> d1 = new Dentaku_seisuu<Object>();
        d1.tasu(5);
        d1.tasu(5);
        System.out.println("d1の答は" + d1.tasu(0));

        Dentaku_seisuu<Object> d2 = new Dentaku_seisuu<Object>();
        d2.tasu(1);
        d2.tasu(1);
        System.out.println("d2の答は" + d2.tasu(0));
      }
}


また、実数用の電卓をDenkatu0クラスから派生させれば、

public class Dentaku_jissuu<D> extends Dentaku0<D> {
      double kotae = 0.0;
      public double tasu(double kazu) {
        return kotae += kazu;
      }
      public double hiku(double kazu) {
        return kotae -= kazu;
      }
}


Denntaku_jisuuクラスを操る見本のコードが、
Dentaku_jissuu_Sousa1

public class Dentaku_jissuu_Sousa1 {
      public static void main( String args[] ) {
          Dentaku_jissuu<Object> d1 = new Dentaku_jissuu<Object>();
        d1.tasu(5.0);
        d1.tasu(5.0);
        System.out.println("d1の答は" + d1.tasu(0.0));

        Dentaku_jissuu<Object> d2 = new Dentaku_jissuu<Object>();
        d2.tasu(1.0);
        d2.tasu(1.0);
        System.out.println("d2の答は" + d2.tasu(0.0));
      }
}


と記述できます。一通りeclipseで検証済みのコードです。
さて、このように数値の型ごとに部分部分でコードがかわってしまうような場合に、抽象クラスを決定しそれを作り込んでいくのです。
もう一つ文字列の足し算と引き算を実装したDentaku_mojiretsuクラスを書いてみました。足し算は単純に引数の文字列を継ぎ足すだけですが、引き算は、引数がオブジェクト内にあれば抜き去り、なければ書き換えずにエラーメッセージを戻します。
Dentaku_mojiretsu.java

public class Dentaku_mojiretsu<D> extends Dentaku0<D> {
      String kotae = "";
      public String tasu(String mojiretsu) {
        return kotae += mojiretsu;
      }
      public String hiku(String mojiretsu) {
      if (kotae.matches(".*" + mojiretsu + ".*"))
            return kotae = kotae.replaceAll(mojiretsu, "");
        else
            System.out.println("'" + kotae + "'の中には、\n'" + mojiretsu + "'は見当たらないので、引けません。");
            return "";
      }
}


この文字列加工用のDentaku_mojiretsuクラスを操る見本が次のコードです。
Dentaku_mojiretsu_Sousa1.java

public class Dentaku_mojiretsu_Sousa1 {
      public static void main( String args[] ) {
          Dentaku_mojiretsu<Object> d1 = new Dentaku_mojiretsu<Object>();
        d1.tasu("明けまして");
        d1.tasu("おめでとうございます。");
        System.out.println("最初の加算のd1の答は「" + d1.tasu("") + "」です。");
        d1.hiku("ございます");
        System.out.println("つぎの加算のd1の答は「" + d1.tasu("") + "」です。");

        Dentaku_mojiretsu<Object> d2 = new Dentaku_mojiretsu<Object>();
        d2.tasu("寿限無、寿限無、");
        d2.tasu("五劫のすり切れ");
        System.out.println("最初の加算のd2の答は「" + d2.tasu("") + "」です。");
        d2.hiku("海砂利水魚");
        System.out.println("つぎの加算のd2の答は「" + d2.tasu("") + "」です。");
      }
}


このように文字列での足したり引いたりする操作を実装することもあるわけです。
他にも、日付の加減算、時刻の加減算、画像の加減算、角度の加減算などとさまざまな派生処理が起こりえます。後手後手の作業で、最初に作った整数用電卓をオーバーライドしてクラスを多様化したり、多態性を活用して引数を違えたメソッドを並べておくこともあることでしょう。
ともかく、ある抽象的な機能を特定のメソッドや変数で定義しておくと派生事項が膨らんでも見通しが良くなります。

抽象的オブジェクトとその派生オブジェクトとの関係を、マンションの間取りとリフォームした部屋として例えたら、部屋の大きさや窓の位置や水回りや柱の大きさや位置は事前に決まっていてこれが抽象的オブジェクトにあたります。そして、入居する人が住居用かオフィス用か押し入れ用かなど用途によって、壁の色や間取りの変更や風呂の特注などのリクエストを取り入れカスタマイズされた部屋の図面が派生クラスに当たります。そして入居可能になった各部屋がインスタンスに当たります。

今回は複数のマイナス評価もいただき、正直焦りましたが、自分なりにOOPの理解が深まり、Dentaku0クラス以下の教材の蓄積ができたので実に勉強になりました。時刻計算用の電卓の実装などまた時間があったら取り組んでみます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/08 12:48

    サイトを見させていただきましたが、各言語の表の所が他言語をコピペしてしまって未完成なのか、多くの間違いが見受けられます。大丈夫でしょうか?

    キャンセル

  • 2017/01/08 13:40

    raccyさん、ご指摘どうもありがとうございます。
    実は昨年、niftyのWebサービス廃止により、あわててラクーカン内に展開したWordPressの記事にコピベして引っ越した状態でして、ちょっとずつ編集し直しているところです。
    とりあえず回答に画像ファイルであげておきますので、参考にしてみて下さい。

    キャンセル

  • 2017/01/08 18:01

    (普通のクラスと対比した)抽象クラスについてが質問の趣旨だと思うのですが、
    この回答ではクラスとインスタンスの説明になってしまっている気が…

    キャンセル

  • 2017/01/09 14:10 編集

    よく考えたら私は確かにオブジェクト指向の基本しか説明していませんでした。
    抽象クラスを具体的に定義して、その継承クラスをインスタンス化する手順を説明すべきでした。
    大きな勘違いをお詫びいたします。
    改めて、抽象クラスの電卓オブジェクトとその継承クラスの実数電卓クラスと整数電卓クラスと文字列電卓クラスを組み直してみたので、本回答を大幅に編集し直します。

    キャンセル

  • 2017/01/09 06:32 編集

    回答で示しているソースコードには、Javaでの「抽象クラス」が一切使われていません。その後もクラスとインスタンスの説明に終始されているようで、これがJavaでの「抽象クラス」にどう関係するのか、私も読み取ることができませんでした。

    また、『抽象的クラス』という言葉を使っているようですが、単に、『抽象的』な『クラス』の事を示すのか、Java用語としての「抽象クラス」(abstract class)の独自な訳語なのかもわかりません。どのような意味で使っているのでしょうか?

    キャンセル

  • 2017/01/09 18:00

    2017/01/09 15:03でのソースコードについて、下記の点が気になります。

    * 抽象クラスを使用しているが、抽象メソッドを使用しておらず、抽象クラスである必要性が無い。
    * 総称型を使用しているが、総称型を各定義で使用しておらず、総称型である必要性が無い。
    * それぞれの子クラスは親クラスの機能等を一切使用しておらず、オーバーライドすらしていない。使用時も多態性を利用して親クラスを変数の型にするなどもしておらず、継承の必要性が無い。

    申し訳ありませんが、Javaをよく知らない人が、想像で書き込んで、なんとかコンパイルを通るようにしただけとしか思えません。一度、Javaの入門書等でJava自体をしっかり勉強することお勧めします。オブジェクト指向は、他言語を知っていれば他も全く同じと言えるほど単純なものではありません。

    キャンセル

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

  • ただいまの回答率 90.86%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    Ruby 数値や真偽値について

    Ruby初心者です。 Rubyはすべてがオブジェクトであるときいたことがあるのですが、 数値や真偽値もオブジェクトなのでしょうか? 疑問に思ったのでどなたか教えていただけないでし

  • 解決済

    javaプログラムから外部プログラムを実行して結果を取得したい

    javaプログラムから外部プログラムを呼び出して、実行結果を取得するようにしたいのですが、具体的なコードでどう書けばいいのでしょうか?

  • 解決済

    リフレクションとは?

    javaのリフレクションを分かりやすく教えて頂けますでしょうか?クラスの情報を取ってきて強引にメソッドを実行。って覚えて問題無いでしょうか?(汗)

  • 解決済

    java

    アプレットとアプリケーション?の違いについてお聞きしたいです。 私の解釈が間違っているかもしれませんが、 アプリケーションの場合mainメソッドがあり public class

  • 受付中

    pythonのクラス コンストラクタについて

    初期化メソッドはクラスのインスタンスがつくられると呼び出される。 クラス変数はすべてのインスタンスで共通の変数であること。 クラス変数をクラス内で書く、もしくはクラスの外部からクラ

  • 解決済

    C#のエラーについて

    C#のプログラムを組んでいると プログラムは、エントリ ポイントに適切な静的 'Main' メソッドを含んでいません。    というエラーが出ることがあるのですが、原因がわかりま

  • 解決済

    Javaのクラス同士のつながりについて

    こんにちは。Javaの質問です。 2つのクラスがあるんですけど、これらはどのようにつながっているのでしょうか。 (うまく説明できません、言い直すと) Mainを実行するとSt

  • 解決済

    swingでボタンクリック時にJavaアプリケーション(jar)を実行する

    Swingによるプログラム作成初心者です。 SwingでGUIプログラムを作成し、ボタンをクリックすると、GUIで入力した値を引数として Jarプログラムを呼び出すという処理を

同じタグがついた質問を見る

  • Java

    12467questions

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

  • オブジェクト指向

    253questions

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