620 likes | 710 Views
サスーンによる Java 勉強会. 2013 年 7 月 27 日. プレゼンター紹介. 名前: 吉村智志 生年月日: 1990 年 4 月 26 日生まれ 出身: 福井県福井市 所属:HAL東京IT学部高度情報処理学科 3 年 夢:自宅に図書館を作る。 カフェ +作業 スペース付き。 近所の子供たちに無料で開放して、PCやプ ログラミング、ビジネスの無料教室をやる !! Facebook: https ://www.facebook.com/satoroll. アジェンダ. ・ dispatcher って なんだっけ?
E N D
サスーンによるJava勉強会 2013年7月27日
プレゼンター紹介 名前:吉村智志 生年月日:1990年4月26日生まれ 出身:福井県福井市 所属:HAL東京IT学部高度情報処理学科3年 夢:自宅に図書館を作る。 カフェ+作業スペース付き。 近所の子供たちに無料で開放して、PCやプ ログラミング、ビジネスの無料教室をやる!! Facebook: https://www.facebook.com/satoroll
アジェンダ ・dispatcherってなんだっけ? ・継承?使ってなんの意味があるの?・オーバーライド?オーバロード?なんじゃあああ・自作例外作ってみたけどなんに使うのこれ?
学ぶ前に~プログラミングの基本~ コンピューターは優秀なアホ ・命令すれば何でも一瞬で終わらせれる 天才的なスキルを持ちながらも、 ・「覚えとけ」って言わないと一瞬でものを忘れる ・知らないことがあると何もできない という天才なのかアホなのか、よくわからない性質を持ちます。
プログラマーとしてこだわるところ 同じコードは二度書かない!! アホなコンピューターに対して 同じ事を何回も命令するのはバカっぽい できました。 2ですね 1と3を足して2で割って イラっ さっき言った処理? なんですかそれは? もっとはっきり言ってほしいんですけど~ 4と8でさっき言った 処理やって 6だよ!つーか足して2で割るんなら最初っからそう言えし。 1秒前のこととか覚えてねえし。 4と8を足して2で割れっつってんだよ。2度言わすな。
←こうならないためにも 「覚えとけ」って言ったことは必ず覚えているので 「この処理方法を覚えとけ」って言って 「さっき言った命令を実行しろ」 って言う方が楽。 sasoonは足して2で割る処理 ですね。 足して2で割るって処理をsasoonって名前で覚えといて 早い 2ですね。 1と3でsasoonやって 6ですね。 4と8でsasoonやって
クラスとは? クラス 関連性のある データ メソッド をまとめたもの 変数とか関数とかの集合体 ある意味「型」そのもの。 StringとかもString っていうクラスを作って型にしてる。 Stringクラスはchar型の変数をごにょごにょして文字列ぽく使えるようにしてる(多分) //////////// さっきの話だと 「aって言う名前の変数に1って数字入れて覚えといて」 「sasoonっていうメソッドを二つの数を足して2で割るっていう処理として覚えといて。」 とかいう覚えてもらうものの塊。
ちなみに 「今ははっきり言えんけど、計算結果によって値変わるかもしれん。 でもその値使って処理したいからその値の名前をaって覚えといて」 って言うのが変数a 変数aを定義する = なんか値入れるものaって名前で覚えといて 次から本題
dispatcherとは? ディスパッチとは「割り当て」って意味です。 サーブレットのソースコードにこんな感じの記述があったと思います protected void forward(String path, HttpServletRequestreq, HttpServletResponseresp) throws ServletException, IOException { //pathは割当先の相対URL RequestDispatcherdispatcher = req.getRequestDispatcher(path); dispatcher.forward(req, resp); }
解説 protected void forward(String path, HttpServletRequestreq, HttpServletResponseresp) throws ServletException, IOException { //pathは割当先の相対URL RequestDispatcherdispatcher = req.getRequestDispatcher(path); dispatcher.forward(req, resp); } ここでdispatcherさんにpathって言うURLを割り当て dispatcherさんはforwardってメソッドを持っている。 効果は、割り当てられたURLのjspに飛ぶって効果
dispatcher.forword()って書いたりforword()って書いたりなんなん?dispatcher.forword()って書いたりforword()って書いたりなんなん? サーブレットにはforword()なんていうメソッドはない。 本当は毎回 String path = “飛びたい先のjspのURL”; RequestDispatcherdispatcher = req.getRequestDispatcher(path); dispatcher.forward(req, resp); こうやって書かなきゃならんけど、めんどくさいから↓のメソッド作ったはず。 protected void forward(String path, HttpServletRequestreq, HttpServletResponseresp) throws ServletException, IOException { //pathは割当先の相対URL RequestDispatcherdispatcher = req.getRequestDispatcher(path); dispatcher.forward(req, resp); } サーブレット内に上みたいなメソッド作ったからforword(path,req,resp)だけ書くだけで良くなった。 よくわかんないままコピペって進めてるとわからんくなる。
小休止次は、継承についてこっから面白くなります.質問あったらどぞー小休止次は、継承についてこっから面白くなります.質問あったらどぞー
継承について ゲームプログラミングを考えるとわかりやすいかも 例 はねスライマ(仮) スライマ(仮) どちらもRPGゲームに出てくる敵キャラだと仮定して、 こいつらがどんなことするか考えてみよう。
スライマ(仮)の特徴 スライマLv10(仮)さんのプロフィール ステータス ・HP:68 ・ちから:32 ・はやさ:48 「たたかう」をしてくる 「ホイミ」を使ってくる これをプログラミングで表すと...
スライマLv10(仮)さんの内部 ※分かりやすくところどころ日本語だけど、プログラミングでは全角文字は使わないようにしよう public class スライマ { int HP = 68; intちから = 32; intはやさ = 48; public void たたかう() { //なんか相手にダメージ与える処理 } public void ホイミ() { //なんか誰かを回復させる処理 } }
じゃあはねスライマさんは? はねスライマLv10(仮)さんのプロフィール ステータス ・HP:52 ・ちから:40 ・はやさ:58 「たたかう」をしてくる 「かまいたち」を使ってくる これをプログラミングで表すと...
はねスライマLv10(仮)さんの内部 public class はねスライマ { int HP = 52; intちから = 40; intはやさ = 58; public void たたかう() { //なんか相手にダメージ与える処理 } public void かまいたち() { //なんか風属性のたたかうより強めなダメージ与える処理 } }
ん?ちょっとまって なんか殆ど一緒じゃね? ↓ それもそのはず。「スライマ」も「はねスライマ」も 同じ「敵モンスター」というカテゴリ。 「敵モンスター」はみんな ・HP・ちから・はやさ ・たたかう・覚えている技 を持っている。
それをコンピューターに教えてあげる どっちも同じ要素持ってるならあらかじめ教えといた方が楽。 こんな感じで public class 敵モンスター { int HP; intちから; intはやさ; public void たたかう() { //なんかダメージ与える処理 } //技は種別によって使えるのが違うので、定義しない }
ここで継承登場 さっき作った「敵モンスター」ってクラスを継承させてスライマクラスを作る extendsを入れると継承するよって意味 public class スライマ extends敵モンスター { HP = 68; ちから = 32; はやさ = 48; public void ホイミ() { //なんか回復させる処理 } //たたかうは親クラスで定義しているのでここで定義する必要なし }
お気づきだろうか? 継承を使ったことによって、わざわざ「たたかう」メソッドの中身を何回も書かなくてよくなった。 →楽!今までは全モンスタークラスにたたかうメソッド書いてたけど 今後、はねスライマ、ぶちスライマ、キングスライマ、ゴールデンスライマ、etc いくら出てきても書く必要がない。 モンスター全種類分だったらどれだけコード量削減できるんですかね... コンピューターの立場から見ても、 「あ、スライマクラスはHP,ちから,はやさって言う変数と たたかうってメソッドを持っているんだな。」 っていうのが分かって楽になる。変数名とかで間違えにくくなるし、Eclipseとか使ってたら入力保管も出るし、いいことづくめ! しかし、継承の利点はもう一個あります
対象を抽象化できる 対象を抽象化?なんのこっちゃ? 難しい言葉は一旦置いといて、スライマさんのホイミの処理を考えてみようか。 ホイミで「はねスライマ」のHPを回復するって処理はこんな感じに書ける public void ホイミ(はねスライマ hane) { //とりあえず一律50回復 hane.HP += 50; }
ここで思い出して欲しいこと Javaは「型」を重要視する言語 宣言時、引数、戻り値、全部「型」指定しないといけない。 ↓こんなことしちゃうと inti= “ああああああああ”; 「あ?何int型に文字列入れようとしてんだよ。 こっちはわざわざintって言ったiの為に狭いメモリやりくりしてint分の 領域開けてやってんだよ。 それをいきなり文字列入れるとか、んなでけえもん入るわけねえだ ろ。」 ….(マジギレかよ^^;) こんな悲しいことになります。 逆に、型を守ることができれば 強固なプログラムになります。
もう一回考えてみよう //ホイミで「はねスライマ」のHPを回復する処理 public void ホイミ(はねスライマhane) { //とりあえず一律50回復 hane.HP += 50; } これ、引数に「はねスライマ型」って書いてあるし、はねスライマしか回復できなくね? スライマさん、僕は回復してくれないとかひどいっすよ 大怪我を負ったキラーパンマー君Lv1(仮)
大怪我を負ったキラーパンマー君Lv1(仮)を回復させるには?大怪我を負ったキラーパンマー君Lv1(仮)を回復させるには? ん、「キラーパンマー」も、「はねスライマ」も、どっちも「敵モンスター」じゃね? ということはこう書けばいいんじゃ?↓ //ホイミで「敵モンスター」のHPを回復する処理 public void ホイミ(敵モンスターteki) { //とりあえず一律50回復 teki.HP+= 50; } 「敵モンスター」はHPって変数持ってたね。 「ホイミ」って処理は敵モンスターの誰かが引数で渡されるから、渡された誰かのHPを50足してやればいいんだね。
これが抽象化 「はねスライマ」も、「キラーパンマー」も「敵モンスター」クラスを継承してるからこそ スライマLv10(仮)さんのホイミ()で回復できる対象に選べるようになった。 親のクラスを継承してるクラスは、親クラス型としても扱うことができる!!!! 因みに、Eclipseさんは親クラスのことをスーパークラスって呼んでるよ。
もし継承してなかったら もし「敵モンスター」を継承してなかったらホイミ()の処理はこう書かなきゃならなかった。 public void ホイミ(はねスライマhane) { //とりあえず一律50回復 hane.HP += 50; } public void ホイミ(キラーパンマーkira) { //とりあえず一律50回復 kira.HP+= 50; } public void ホイミ(キングスライマking) { //とりあえず一律50回復 king.HP+= 50; } //他、モンスター数百種類分の引数の型のホイミ()を定義しなければならない。だるっ!
なので、大事なこと 今回のJavaの課題、いきなりコード書き始めた人も多かったと思います。 しかし、プログラマーならば、まずコードを書く前に、 ・どんな機能があるか ・その機能の為にどんなメソッドが必要か ・その機能の為にどんな変数が必要か ・それらは、どういった塊に纏められるか 等を考えて、それらをクラスにしていきます。 クラス一つ一つに決まった意味を持たせます。 それが「クラス設計」です。どんなプログラムだったら使いやすいか、分かり易いかを考えてからコードを書きましょう。 さっきの例だったらキャラクタークラスを継承して味方クラスと敵クラスに分けて欲しいわ。あと、覚える技系統ごとに 技クラスもつくって、キャラクタークラスの中に技クラスを入れて欲しいわ。
小休止因みに、さっきオーバーロード使ってました。次はオーバーロードとオーバーライドについてです。質問あればどぞ。小休止因みに、さっきオーバーロード使ってました。次はオーバーロードとオーバーライドについてです。質問あればどぞ。
オーバーロードについて さっきのダメなパターンのホイミ()の書き方 public void ホイミ(はねスライマhane) { //とりあえず一律50回復 hane.HP += 50; } public void ホイミ(キラーパンマーkira) { //とりあえず一律50回復 kira.HP += 50; } public void ホイミ(キングスライマking) { //とりあえず一律50回復 king.HP += 50; } これ、実はオーバーロードしてます。
どの辺がオーバーロード? オーバーロードとは、同じメソッドを違う「型」の引数でもう一個定義してあげる事。 public void ホイミ(はねスライマhane) { //とりあえず一律50回復 hane.HP += 50; } public void ホイミ(キラーパンマーkira) { //とりあえず一律50回復 kira.HP += 50; } 「はねスライマ型」でも「キラーパンマー型」でも引数に持つことができる。 これがオーバーロード。 でも、さっき言った通りこれは悪い例。
じゃあどんな時に使うのさ? 例えば、キラーパンマーは50しか回復しないけど、「はねスライマ」だけHPが100回復する「ラブリーはねスライマ」って技があったら public void ラブリーはねスライマ(キラーパンマー kira) { kira.HP += 50; } //はねスライマは効果違う public void ラブリーはねスライマ(はねスライマ hane) { hane.HP += 100; } 同じ「ラブリーはねスライマ」って技なのに、「はねスライマ」のときだけ効果が違うようになった!! ラブリーはねスライマ! 50 ラブリーはねスライマ! 100
他にもこんなことできる ・「ラブリーはねスライマ」が「はねスライマ」だけ2体選択して回復できる技なら public void ラブリーはねスライマ(キラーパンマー kira) { kira.HP += 50; } //はねスライマは効果違う public void ラブリーはねスライマ(はねスライマhane) { hane.HP += 100; } //はねスライマなら2体選ぶことができる!! public void ラブリーはねスライマ(はねスライマhane1,はねスライマhane2) { hane1.HP += 100; hane2.HP += 100; } ラブリーはねスライマ! 100 100 はねスライマさんだけずるいっす
オーバーロードのいいところ ・同じメソッドなのに、違う引数の「型」で書ける ・同じメソッドなのに、違う引数の数が持てる ・引数の「型」とか、数に応じて処理の中身を変えられる つまり、 一つのメソッドにその時々に応じて色んな処理をさせることができる
オーバーライドの前に オーバーライドについて学ぶ前に思ってほしいこと。 オーバーロードとオーバーライド、名前が似てますが、そんなこと気にしなくていいです。 オーバーロードって言うのは同じメソッドだけど引数によって色々変えられるていうのはさっき勉強しましたね? 大事なのは、Javaにはメソッドの引数を変えることで処理の中身を変えられるってことを知っているかどうか。 それをオーバーロードって読んでるだけで、オーバーロードだろうがオーバードーロだろうがなんだっていいんです。 「オーバーライドとオーバーロードってどっちがどっちだっけ?」って悩むのは筆記試験前だけで十分。
オーバーライドとは? 「親クラスで定義されているメソッドを子クラスで再定義すること」 は?よくわからんので、後回しにして、なんか言いたいことがある輩がいるそうです。 俺様の「たたかう」は普通のやつより2倍強えんだよ。他のやつと一緒にすんな。 好戦的ないたずらもぐマLv99(仮)さん なんかほざいてますね。一体何のことを言っているのでしょうか?
好戦的ないたずらもぐマLv99(仮)さんが言っていること好戦的ないたずらもぐマLv99(仮)さんが言っていること とりあえず、好戦的ないたずらもぐマLv99(仮)さんの中身をのぞいてみましょうか。 public class いたずらもぐマ extends 敵モンスター { HP = 99; ちから = 200; はやさ = 99; public void あなほり() { //なんかなんか穴掘る処理 } //たたかうは親クラスで定義しているのでここで定義する必要なし } これのことを言ってんだよ!
好戦的ないたずらもぐマLv99(仮)さんの「たたかう」を他のキャラクターの2倍の威力にするには?好戦的ないたずらもぐマLv99(仮)さんの「たたかう」を他のキャラクターの2倍の威力にするには? 現在の「たたかう」の処理はこうなっています。 public class 敵モンスター { int HP; intちから; intはやさ; //「たたかう」はとりあえず一律50ダメージ public void たたかう(味方キャラ mikata) { mikata.HP -= 50; } }
それをこうしてやればいい いたずらもぐマクラスだけ、「たたかう」の威力を2倍にしてやればいのです。 public class いたずらもぐマ extends 敵モンスター { HP = 99; ちから = 200; はやさ = 99; public void あなほり() { //なんか穴掘る処理 } //親クラスのたたかう()を再定義 public void たたかう(味方キャラ mikata) { mikata.HP -= 100; } }
はい、今オーバーライドしましたー! いたずらもぐマクラスで親クラスである敵モンスタークラスのたたかう()を再定義したため、 「いたずらもぐマ」のたたかう()は100ダメージ、それ以外のモンスターのたたかう()は50ダメージ与える処理になりました。 俺様のたたかう()はその辺のやつとは違うんだ。 他の敵モンスターと一緒にされちゃ困る。 つまり、親クラスですでに定義されているメソッドを 子クラスで再定義するということです。 あれ?最初に言ったことと同じ事言ってる!
ルール的なこと 下記にオーバーロードのルール的な事 なんか色々書いてありますが、気にしなくていいです。 この辺のことは、コード書いてれば自然とEclipseさんが教えてくれます。 1.戻り値、メソッド名、引数の型、数が同じであること 2.public →private 等、アクセスレベルを厳しくして再定義はできない 3.親クラスのthrowで指定した例外を無視して例外をthrowできない 4.finalがついてるやつはオーバーロードできない 5.abstractがついてるやつはオーバーロードされなきゃならん。さもなくば自分がabstractになる
オーバーライドのいいところ さっきみたいに、 だいたいみんなおんなじことやるんだけど、コイツの時だけちょっと違う なんて時に使えます。 オーバーライドなんて言葉意識しなくても自然に使うことになるので、 親クラスのメソッドは、子クラスで書き直せる ってことを知ってれば大丈夫です。 ちなみにEclipseさんは子クラスのことをサブクラスって呼んでるよ。
小休止質問あったらどぞー次は自作例外について小休止質問あったらどぞー次は自作例外について
自作例外を学ぶ前に 自作例外を作る意味ですが、それを考える前に、まず例外処理を行うメリットについて考えてみましょう。 ここまでの内容で、疑問に思ったことはありませんか? ホイミ()で回復しようにも既に死んじゃってたらどうしよう? それか詠唱中のスライマさんほっといて逃げ出すかも。 かわいそうなキラーパンマー君Lv1(仮)
かわいそうなキラーパンマー君Lv1(仮)が言ってることかわいそうなキラーパンマー君Lv1(仮)が言ってること 彼が言っているのはこういうことですね。 ホイミ! 既に死んでいる! できない! OR 逃げ出している! ホイミを使う事前条件として、1.生きていること,2.逃げていないこと が挙げられますね! ※ここから説明するのは、実際のゲームではあり得ることなので「例外」としては 適切ではありませんが、分かり易さ重視の為に「例外」として説明します。
ここでちょっと整理 • ここで、ホイミ()を使用するときのシナリオを整理しましょうか。 • ホイミ()のシナリオ • { • 1.ホイミ()使用を選択する • 2.回復対象のモンスターを選ぶ • 3.対象を回復させる • { • 3a.モンスターが生きている場合(成功シナリオ) • //50回復 • } • { • 3b.モンスターが死んでいた場合(失敗シナリオ) • //死んでる例外 • } • { • 3c.モンスターが逃げていた場合(失敗シナリオ) • //逃げてる例外 • } • }
例外とか気にしないで流れを作ってみたZE☆ //取り合えず事前条件をチェックDA! //1.死んでないか確かめる! if(キラーパンマー== 死んでる){ //キラーパンマーは既に死んでます。ってエラー } //2.逃げていないか確かめる! else if(キラーパンマー!= 逃げてる) { //キラーパンマーは逃げ出しています。ってエラー } //3.ようやく正しい時の処理 else { スライマ.ホイミ(キラーパンマー); }
ん?ちょっとまって。 これってホイミ使うときは毎回いちいち事前に死んでないか逃げてないか確認しなきゃならないの?めんどくさ!確認とか忘れるし! 毎回毎回確認してられっか! ホイミとか毎日何百回も使ってんだよ!