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

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

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

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

オブジェクト指向

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

Q&A

解決済

12回答

6323閲覧

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

mr0237

総合スコア164

Java

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

オブジェクト指向

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

0グッド

5クリップ

投稿2017/01/08 01:36

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

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

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

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

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

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

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

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

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

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

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

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

ozwk

2017/01/08 04:57 編集

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

2017/01/08 05:01

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

2017/01/11 06:33 編集

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

回答12

0

抽象とは?

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

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

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

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

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

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

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

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

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

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

実際に使われるケース

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

投稿2017/01/08 06:08

miyabi-sun

総合スコア21158

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

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

0

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

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

投稿2017/01/08 07:10

raccy

総合スコア21735

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

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

0

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

抽象クラスではなくてインタフェースですが、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)と、統一された方法でリストを操作することができるのです。これが、抽象クラスやインタフェースのメリットです。

投稿2017/01/08 02:13

swordone

総合スコア20651

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

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

0

抽象クラスがある理由

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

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

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

java

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

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

java

1 2class MyFile extends Closeable { // MyFileはclose()できることを保証します 3 String filePath; 4 .... 5 6 void close(){ 7 /** close()を実装しないとコンパイルエラーしちゃうので **/ 8 /** MyFileには、close()が呼び出せることが保証されます **/ 9 } 10} 11

java

1 2class MySocket extends Closeable { // MySocketはclose()できることを保証します 3 long id; 4 ... 5 6 void close(){ 7 /** MySocketには、close()が呼び出せることが保証されます **/ 8 } 9} 10

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

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

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

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

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

java

1 2abstract class Orderable{ 3 4 5 // [戻り値] 6 // this == ordなら 0 7 // this < ordなら 負の数 8 // this > ordなら 正の数 9 abstract int compare(Orderable ord); 10 11 12 // lessThan() 13 // graterThan() 14 // isTheSame() 15 // はcompareを使って実装できます 16 17 boolean lessThan(Orderable ord){ 18 return compare(ord) < 0; 19 } 20 21 boolean graterThan(Orderable ord){ 22 return compare(ord) > 0; 23 } 24 25 boolean isTheSame(Orderable ord){ // [^2] 26 return compare(ord) == 0; 27 } 28}

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

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

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

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

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

設計の問題というのは、

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

java

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

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

java

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

改良版Orderable

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

java

1abstract class Orderable<T>{ 2 3 4 // [戻り値] 5 // this == ordなら 0 6 // this < ordなら 負の数 7 // this > ordなら 正の数 8 abstract int compare(T ord); 9 10 11 // lessThan 12 // graterThan 13 // isTheSame 14 // はcompareを使って実装できます 15 16 boolean lessThan(T ord){ 17 return compare(ord) < 0; 18 } 19 20 boolean graterThan(T ord){ 21 return compare(ord) > 0; 22 } 23 24 boolean isTheSame(T ord){ // [ここは気にしないで] equalsにしなかったのは、Object#equals(Object)を正しく実装できないからです 25 return compare(ord) == 0; 26 } 27} 28 29class MyInteger extends Orderable<MyInteger>{ 30 int value; 31 public MyInteger(int value){ 32 this.value = value; 33 } 34 35 36 int compare(MyInteger that){ // 注意:引数の名前はthatです 37 // this == thatなら0、this < thatなら負の数、this > thatなら正の数にちゃんとなります 38 return this.value - that.value; 39 } 40 41} 42

使い方は

java

1class MyInteger extends Orderable<MyInteger>{ 2 int value; 3 public MyInteger(int value){ 4 this.value = value; 5 } 6 7 8 int compare(MyInteger that){ // 注意:引数の名前はthatです 9 // this == thatなら0、this < thatなら負の数、this > thatなら正の数にちゃんとなります 10 return this.value - that.value; 11 } 12 13} 14 15

java

1MyInteger i1 = new MyInteger(10); 2MyInteger i2 = new MyInteger(5); 3 4System.out.println(i1.lessThan(i2)); // => false 5System.out.println(i1.graterThan(i2)); // => true 6System.out.println(i1.isTheSame(i2)); // => false 7

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

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

投稿2017/01/08 05:27

編集2017/01/08 05:33
grovion

総合スコア145

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

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

0

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

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

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

ファイル名:Jyuyou.java

java

1abstract class{// 抽象クラス 2 3 int i = 0; 4 5 abstract void 否認();// 自分の死そのものを疑う段階 6 7 abstract void 怒り();// 自分が死ぬことへの怒りを感じている段階 8 9 abstract void 取り引き();// 死を免れようとあがき回る段階 10 11 abstract void 抑うつ();// 気分が落ち込み何もできない段階 12 13 abstract void 受容();// 死をついに受け入れた段階 14 15 void 死の受容過程() {// 上記過程の連続再生 16 17 System.out.println("死の受容例" + (i + 1) + "人目"); 18 slp(); 19 System.out.println("\n---" + (i + 1) + "人目:" + "死の受容の過程1~否認~---"); 20 slp(); 21 否認(); 22 slp(); 23 System.out.println("\n---" + (i + 1) + "人目:" + "死の受容の過程2~怒り~---"); 24 slp(); 25 怒り(); 26 slp(); 27 System.out.println("\n---" + (i + 1) + "人目:" + "死の受容の過程3~取り引き~---"); 28 slp(); 29 取り引き(); 30 slp(); 31 System.out.println("\n---" + (i + 1) + "人目:" + "死の受容の過程4~抑うつ~---"); 32 slp(); 33 抑うつ(); 34 slp(); 35 System.out.println("\n---" + (i + 1) + "人目:" + "死の受容の過程5~受容~---"); 36 slp(); 37 受容(); 38 slp(); 39 System.out.println("\n\n\n\n"); 40 slp(); 41 42 } 43 44 void set(int o) {// 何人目か 45 i = o; 46 } 47 48 void slp() {// 表示間隔 49 try { 50 Thread.sleep(600); 51 } catch (Exception e) { 52 } 53 } 54 55} 56 57class 死を待つ人1 extends{// 抽象クラスを実装したクラス1 58 59 void 否認() { 60 System.out.println("私は癌ではありません 検査のやり直しを要求します"); 61 } 62 63 void 怒り() { 64 System.out.println("何で俺が死ななきゃならないんだ! 死にたくないって言ってるだろ!"); 65 } 66 67 void 取り引き() { 68 System.out.println("すみません 癌の特効薬があると言うのはこちらですか"); 69 } 70 71 void 抑うつ() { 72 System.out.println("死にたくありません 僕は死にたくないんです"); 73 } 74 75 void 受容() { 76 System.out.println("最近、死ぬのも悪くないって思えるようになったんです"); 77 } 78 79} 80 81class 死を待つ人2 extends{// 抽象クラスを実装したクラス2 82 83 void 否認() { 84 System.out.println("あの医者俺が死ぬなんて嘘なんでついたんだろ"); 85 } 86 87 void 怒り() { 88 System.out.println("やめろ・・・死ぬとかそんなの本人に言っていいと思ってるのか!"); 89 } 90 91 void 取り引き() { 92 System.out.println("分かりました 分かりました食事療法で少しでも生きられるんですね"); 93 } 94 95 void 抑うつ() { 96 System.out.println("嫌だ・・死にたくない・・・・耐えられない・・・・"); 97 slpl(); 98 for (int i = 0; i < 400; i++) { 99 System.out.print("死にたくない "); 100 } 101 System.out.println(); 102 } 103 104 void 受容() { 105 System.out.println("昨日お迎えが来る夢を見たんです"); 106 } 107 108 void slpl() { 109 try { 110 Thread.sleep(2000); 111 } catch (Exception e) { 112 } 113 } 114 115} 116 117class 死を待つ人3 extends{// 抽象クラスを実装したクラス3 118 119 void 否認() { 120 System.out.println("昨日死の宣告を受ける夢を見た リアルだったが夢は夢だ そうだあれは夢だ"); 121 } 122 123 void 怒り() { 124 System.out.println("俺が死んだら残された皆はどうなるんだ! そんなの認められるはずがないだろうが!"); 125 } 126 127 void 取り引き() { 128 System.out.println("この万病に効くエキスさえあれば・・・"); 129 } 130 131 void 抑うつ() { 132 for (int i = 0; i < 25; i++) { 133 System.out.print("嫌だ・・・死にたくない・・・ "); 134 slpl(); 135 System.out.print("あの頃・・・食事に気を付けてさえいれば・・・ "); 136 slpl(); 137 System.out.print("これは夢だ・・・夢だ・・・ "); 138 slpl(); 139 } 140 System.out.println(); 141 } 142 143 void 受容() { 144 System.out.println("僕が死ぬことは最初から定められていた運命だったんです だからこれは仕方のない事なんです"); 145 } 146 147 void slpl() { 148 try { 149 Thread.sleep(50); 150 } catch (Exception e) { 151 } 152 } 153 154} 155 156class Jyuyou { 157 158 public static void main(String[] args) { 159 160 死 a[] = new[3];// 配列変数aに全ての実装クラスのインスタンスを一括して入れられる(多態性) 161 162 a[0] = new 死を待つ人1(); 163 a[1] = new 死を待つ人2(); 164 a[2] = new 死を待つ人3(); 165 166 for (int i = 0; i < 3; i++) {// このfor文の中で行われる操作は 167//a配列の中に入るクラス死の実装クラスをどれだけ増やしても同じで済む 168 169 a[i].set(i); 170 a[i].死の受容過程(); 171 172 } 173 174 } 175 176} 177

投稿2017/01/08 06:19

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

ベストアンサー

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

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

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

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

投稿2017/01/08 02:30

編集2017/01/08 02:31
catsforepaw

総合スコア5938

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

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

mr0237

2017/01/08 05:03

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

2017/01/08 05:53

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

0

マウスを例にします。

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

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

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

投稿2017/01/08 02:14

編集2017/01/08 02:15
yona

総合スコア18155

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

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

0

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

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

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

投稿2017/01/08 06:02

HogeAnimalLover

総合スコア4830

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

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

0

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

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

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

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

java

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

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

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

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

java

1class ConsoleWriter extends Writer{ 2 void Write(String text){ 3 System.out.println(text); 4 } 5}

java

1public class Main { 2 public static void main(String[] args) throws Exception { 3 Writer w = new ConsoleWriter(); // 実用的にはwの中身はいろいろ選択できるようにする 4 HelloWorld.Greet(w); 5 } 6}

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

投稿2017/01/08 05:32

ozwk

総合スコア13521

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

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

0

参考情報:

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

投稿2017/01/08 05:21

katoy

総合スコア22324

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

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

0

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

投稿2017/01/08 04:56

編集2017/01/08 06:50
seastar3

総合スコア2285

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

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

swordone

2017/01/08 05:27 編集

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

2017/01/08 05:38 編集

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

2017/01/08 06:46

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

0

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

Dentaku0.java

Java

1public abstract class Dentaku0<T> { 2 private Object kotae; 3 public <T> void tasu(){}; 4 public <T> void hiku(){}; 5}

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

Java

1public class Dentaku_seisuu<D> extends Dentaku0<D> { 2 int kotae = 0; 3 public int tasu(int kazu) { 4 return kotae += kazu; 5 } 6 public int hiku(int kazu) { 7 return kotae -= kazu; 8 } 9}

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

Java

1public class Dentaku_seisuu_Sousa1 { 2 public static void main( String args[] ) { 3 Dentaku_seisuu<Object> d1 = new Dentaku_seisuu<Object>(); 4 d1.tasu(5); 5 d1.tasu(5); 6 System.out.println("d1の答は" + d1.tasu(0)); 7 8 Dentaku_seisuu<Object> d2 = new Dentaku_seisuu<Object>(); 9 d2.tasu(1); 10 d2.tasu(1); 11 System.out.println("d2の答は" + d2.tasu(0)); 12 } 13}

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

Java

1public class Dentaku_jissuu<D> extends Dentaku0<D> { 2 double kotae = 0.0; 3 public double tasu(double kazu) { 4 return kotae += kazu; 5 } 6 public double hiku(double kazu) { 7 return kotae -= kazu; 8 } 9}

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

Java

1public class Dentaku_jissuu_Sousa1 { 2 public static void main( String args[] ) { 3 Dentaku_jissuu<Object> d1 = new Dentaku_jissuu<Object>(); 4 d1.tasu(5.0); 5 d1.tasu(5.0); 6 System.out.println("d1の答は" + d1.tasu(0.0)); 7 8 Dentaku_jissuu<Object> d2 = new Dentaku_jissuu<Object>(); 9 d2.tasu(1.0); 10 d2.tasu(1.0); 11 System.out.println("d2の答は" + d2.tasu(0.0)); 12 } 13}

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

Java

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

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

Java

1public class Dentaku_mojiretsu_Sousa1 { 2 public static void main( String args[] ) { 3 Dentaku_mojiretsu<Object> d1 = new Dentaku_mojiretsu<Object>(); 4 d1.tasu("明けまして"); 5 d1.tasu("おめでとうございます。"); 6 System.out.println("最初の加算のd1の答は「" + d1.tasu("") + "」です。"); 7 d1.hiku("ございます"); 8 System.out.println("つぎの加算のd1の答は「" + d1.tasu("") + "」です。"); 9 10 Dentaku_mojiretsu<Object> d2 = new Dentaku_mojiretsu<Object>(); 11 d2.tasu("寿限無、寿限無、"); 12 d2.tasu("五劫のすり切れ"); 13 System.out.println("最初の加算のd2の答は「" + d2.tasu("") + "」です。"); 14 d2.hiku("海砂利水魚"); 15 System.out.println("つぎの加算のd2の答は「" + d2.tasu("") + "」です。"); 16 } 17}

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

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

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

投稿2017/01/08 03:16

編集2017/01/09 10:01
seastar3

総合スコア2285

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

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

raccy

2017/01/08 03:48

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

2017/01/08 04:40

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

2017/01/08 09:01

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

2017/01/09 05:10 編集

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

2017/01/08 21:32 編集

回答で示しているソースコードには、Javaでの「抽象クラス」が一切使われていません。その後もクラスとインスタンスの説明に終始されているようで、これがJavaでの「抽象クラス」にどう関係するのか、私も読み取ることができませんでした。 また、『抽象的クラス』という言葉を使っているようですが、単に、『抽象的』な『クラス』の事を示すのか、Java用語としての「抽象クラス」(abstract class)の独自な訳語なのかもわかりません。どのような意味で使っているのでしょうか?
raccy

2017/01/09 09:00

2017/01/09 15:03でのソースコードについて、下記の点が気になります。 * 抽象クラスを使用しているが、抽象メソッドを使用しておらず、抽象クラスである必要性が無い。 * 総称型を使用しているが、総称型を各定義で使用しておらず、総称型である必要性が無い。 * それぞれの子クラスは親クラスの機能等を一切使用しておらず、オーバーライドすらしていない。使用時も多態性を利用して親クラスを変数の型にするなどもしておらず、継承の必要性が無い。 申し訳ありませんが、Javaをよく知らない人が、想像で書き込んで、なんとかコンパイルを通るようにしただけとしか思えません。一度、Javaの入門書等でJava自体をしっかり勉強することお勧めします。オブジェクト指向は、他言語を知っていれば他も全く同じと言えるほど単純なものではありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問