C言語でプログラムを作成、実行できますか?

プログラミングが身についているか確認しよう

実行例と同じになるようにプログラムを作成、実行しよう。

[課題1] BMI算出

身長[cm]は?: 170
体重[kg]は?: 60
BMIは20.761246です。

「170」と「60」はキーボードからの入力。BMIの計算方法はBMIと適正体重(keisanサービス)が参考になる。

[課題2] 100以上200未満の数のうち、3の倍数でないものを空白区切で表示せよ

100 101 103 104 106 107 109 110 112 113 115 116 118 119 121 122 124 125 127 128 130 131 133 134 136 137 139 140 142 143 145 146 148 149 151 152 154 155 157 158 160 161 163 164 166 167 169 170 172 173 175 176 178 179 181 182 184 185 187 188 190 191 193 194 196 197 199

[課題3] 200以上300未満でFizzBuzz、空白区切

3の倍数の時に「Fizz」、5の倍数の時に「Buzz」と表示する。ただし、3と5の両方の倍数の時には「FizzBuzz」と表示する。3もしくは5の倍数でない時にはその数字を表示する。

Buzz Fizz 202 203 Fizz Buzz 206 Fizz 208 209 FizzBuzz 211 212 Fizz 214 Buzz Fizz 217 218 Fizz Buzz 221 Fizz 223 224 FizzBuzz 226 227 Fizz 229 Buzz Fizz 232 233 Fizz Buzz 236 Fizz 238 239 FizzBuzz 241 242 Fizz 244 Buzz Fizz 247 248 Fizz Buzz 251 Fizz 253 254 FizzBuzz 256 257 Fizz 259 Buzz Fizz 262 263 Fizz Buzz 266 Fizz 268 269 FizzBuzz 271 272 Fizz 274 Buzz Fizz 277 278 Fizz Buzz 281 Fizz 283 284 FizzBuzz 286 287 Fizz 289 Buzz Fizz 292 293 Fizz Buzz 296 Fizz 298 299

詳細はFizz Buzz (Wikipedia)を参照。

その他

プログラムを作ってみよう。

Map(コレクション)の基礎

前回のまとめ

  • 「コレクション」とはデータの集合のこと。Javaではコレクションを扱うためのコレクションフレームワークが標準で含まれている。
  • Listは順序性があるコレクション
  • 教科書: P.178, P.190-200
  • サンプル
  • Thymeleafで繰り返し処理はth:eachを使う。Javaの拡張for文のようなものと思えば良い。

Spring Boot 2.0.2

Spring Boot 2.0.2がリリースされた。
自分のプロジェクトもupdateしよう。build.gradleを書き換えればよい。


JavaのMapの基礎

英和辞書を作ろう

ポイント:

  • テンプレート:
    • 共通部分はth:fragmentで定義し、th:include等で呼び出すことができる。Thymeleaf 3からはth:includeは非推奨とのことなので、th:insertかth:replaceを使おう。
    • th:ifを使うと条件によって表示することができる。
  • コントローラ:
    • 辞書を表すマップをコントローラのフィールドとして作る。インスタンス化が必要なことに注意する。
    • マップにキーと値を追加する(27行目)。
    • マップから値を取得する(38行目)。

List(コレクション)の基礎

前回のまとめ

前回の「ポイント」を再掲

  • テンプレート:
    • form要素の内側でinput要素を使う。
    • form要素のaction属性で値をどこにリクエストするか指定する。
    • form要素のmethod属性の違い: getはフォームの値がURLに含まれる。postはURLに含まれない(リクエストボディに記述される)
    • input要素のtype属性で種類が指定できる: textはテキストフォーム、submitは送信ボタン。
    • input要素の区別はname属性で行う。
  • コントローラ(主に14〜26行目):
    • フォームからの値を受け取るには、メソッドに引数を加え、@RequestParamアノテーションをつける。
    • @RequestMappingアノテーションはgetでもpostでも動作する。

JavaのListの基礎

掲示板を作る

コメントだけの掲示板

ポイント:

  • テンプレート:
  • コントローラ(主に16〜51行目):
    • コメント(文字列)を格納するリストをコントローラのフィールドとして作る。インスタンス化が必要なことに注意する。
    • リストにコメントを追加する(48行目)。
    • 「コメントを追加しました。」のページが必要なければ、リダイレクトさせることができる(49行目をコメントにして、50行目のコメントを外す)。

名前と投稿時刻を加えた掲示板


予習

Javaのコレクション(特に下記)調べよう。

  • Mapを使いたい(教科書P.215)
  • Mapに要素を追加したい(教科書P.218)
  • Mapの値を取得したい(教科書P.221)

フォームの基礎

前回のまとめ

  • @ResponseBodyアノテーションをつけない場合はテンプレートエンジンを使う設定なる。
  • 使うテンプレートはメソッドの戻り値で指定する。
  • テンプレートに値を渡すには、ModelMapクラスを使う。
  • テンプレートで文字列を埋め込むには、要素(タグ)の属性として「th:text=”${モデルの名前}”」を指定する。

フォームを使う

「BMIの計算」を例として、「ブラウザから何か入力して、サーバで処理を行い、結果をブラウザで表示する」ということを行ってみよう。サーバに何か送るにはフォーム(HTMLのformタグとその関連タグ)を使う。

処理の流れを次のシーケンス図に示す。

sequence

テンプレートとコントローラを作成しよう。

ポイント:

  • テンプレート:
    • form要素の内側でinput要素を使う。
    • form要素のaction属性で値をどこにリクエストするか指定する。
    • form要素のmethod属性の違い: getはフォームの値がURLに含まれる。postはURLに含まれない(リクエストボディに記述される)
    • input要素のtype属性で種類が指定できる: textはテキストフォーム、submitは送信ボタン。
    • input要素の区別はname属性で行う。
  • コントローラ(主に14〜26行目):
    • フォームからの値を受け取るには、メソッドに引数を加え、@RequestParamアノテーションをつける。
    • @RequestMappingアノテーションはgetでもpostでも動作する。

formt要素のaction属性を書かない場合は、同じURLにリクエストを送ることになる。action属性を使わない例は次のようになる。

ポイント:

  • テンプレート:
    • form要素のaction属性を書かない場合は同じURLにリクエストする。
  • コントローラ(主に28〜40行目):
    • @GetMappingアノテーションはgetだけで動作し、@PostMappingアノテーションはpostだけで動作する。
    • @GetMappingアノテーションと@PostMappingアノテーションで同じパスを指定することができる。

復習

テンプレートを使う

前回のまとめ

  • Spring BootのアプリケーションはSPRING INITIALIZRでプロジェクトの雛形を作成することができる。
  • @Controllerアノテーション: クラスに付与するアノテーションで、そのクラスがコントローラであることを示す。「コントローラとは何か」は今回解説する。
  • @RequestMappingアノテーション: アクセス先のパス(URLの後ろ側)を表す。クラスとメソッドにそれぞれつけることができ、結合したものが最終的なパスを表す。
  • @ResponseBodyアノテーション: メソッドに付与するアノテーションで、戻り値をそのままブラウザに返すことを表す。
  • サーバのポート番号はデフォルトで8080だが、application.propertiesファイルに設定を記述することで変えることができる。

初学者のためのFAQ

 

  • Q: これまでクラスを作った(書いた、定義した)ら、new演算子でインスタンス化しないと使えなかったけど、コントローラのインスタンス化は?

    A: フレームワークがインスタンス化してくれる。フレームワークとは「全体の処理・流れ定義(実装)されており、その中の一部に自分のコードを組み込んでいくシステム」のこと。わかりやすい解説としてSoftware frameworkソフトウエアのフレームワークとはなにか等。


テンプレートを使う

前回は、文字をブラウザに表示したが、これでは表現力がなさすぎる。HTMLで表示するようにしてみよう。もちろん、コントローラからHTMLで出力するようにしてもいいが、ものすごく大変なので、テンプレートを用意しそこに文字をはめ込んで表示するようにしよう。

Spring Web MVC framework

これから作るウェブアプリケーションはSpringのWeb MVCフレームワークを利用している。このフレームワークにおける処理の流れを次の図に示す(http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-servletより引用)。

Mvc

フロントコントローラがリクエストを適切なコントローラに渡し、コントローラが出力するデータをビュー(テンプレート)が表示するという仕組みだ。このうち、自分で作るのは、「コントローラ」と「ビューテンプレート」である。コントローラからビューに「モデル(要するにデータ)」を渡すことによって表示内容を動的に(つまりメソッド実行時に)変えることができる。

テンプレートエンジン(テンプレートに関する処理を行うソフトウェア)は、前回、SPRING INITIALIZRでプロジェクト作成時に指定したThymeleafが使われる。

コントローラ

テンプレートを利用するコントローラを作成しよう。

前回との違い:

  • メソッドに@ResponseBodyがつかなくなること。これによりメソッドのreturnで指定した文字列がブラウザに直接送られるのではなく、テンプレートを使うようになる。メソッドのreturnで指定する文字列は「どのテンプレートを使うか」を指定するために使う。
  • テンプレートに値を渡すには、ModelMapクラスを使う。メソッド引数としてModelMapを指定すると使えるようになる(フレームワークがテンプレートに引き渡すためのインスタンスを作ってくれる)。ModelMapのaddAttributeメソッドでテンプレートに渡すモデルの「名前」と「値」を指定する。

テンプレート

テンプレートを置く場所(基点)はResourcesのtemplatesだ。コントローラで「lect02/hello」とした場合、templatesの中にlect02というディレクトリを作り、その中にhello.htmlというファイルを作る。

NetBeansのパッケージの表示の仕方によっては、作業が難しい。プロジェクトウィンドウの背景部分を右クリックし、「Javaパッケージの表示方法」を「ツリー」にすると階層構造がわかりやすい。または、プロジェクト表示ではなく、ファイル表示にするとわかりやすい。

templates

コントローラでは3つのテンプレートを指定している。それぞれ作成しよう。

ポイント

  • 単に表示をするだけの場合は素のHTMLで良い。Thymeleafの機能を使う場合は「th:」から始まる要素(タグ)や属性を使う。
  • htmlタグの属性に追加した「xmlns:th=”http://www.thymeleaf.org”」は名前空間の指定。最近のThymeleafならなくても動くが、つけておいたほうが良い。
  • 文字列を埋め込む場合は、要素(タグ)の属性として「th:text=”${モデルの名前}」を指定する。子ノード(要するにタグに挟まれたところ)がモデルの値で置き換わる。他にも指定方法がある。counter.htmlにいくつか例を示す。

実行・確認

実行して、確認しよう。

どのようなHTMLが出力されているかはChromeのデベロッパーツール等を使うと良い。


復習

NetBeansでSpring Bootアプリケーションの開発を始める

プロジェクトの雛形を作成

  1. ブラウザで「http://start.spring.io」にアクセスする。
  2. 「Gradle Project」を選択する。
  3. 「Java」を選択する。
  4. 「2.0.1」を選択する。
  5. グループIDとして、ここでは「ユーザ名」を使う。
  6. アーティファクトIDは、ここでは「webapp」とする。
  7. 利用する依存ライブラリを入力する。名前の一部を入力すると選択肢が現れるのでクリックして選択する。ここでは「Web」と「Thymeleaf」を選択する。
  8. 選択されたものが表示されているので「Web」と「Thymeleaf」が選択されていることを確認する。
  9. クリックするとプロジェクトのファイル(ZIPファイル)のダウンロードが始まる。

Spring Initializr

NetBeansでインポート

メニューから[ファイル]→[プロジェクトをインポート]→[ZIPから]を選択し、ダウンロードしたファイル(webapp.zip)を指定してインポートする。

project

Spring Bootアプリケーションの実行

アプリケーションを実行するためのタスクが定義されているため、それを使う。

プロジェクトを右クリックして、[Task]→[boot]→[bootRun]を選択する。

アプリケーションが立ち上がると、出力ウィンドウの最後に「Started WebappApplication」と表示される。

その1行前に「Tomcat started on port(s): 8080 (http)」と出力されているということは、8080番ポートにアクセスすれば何らかの反応があるはずである。http://localhost:8080/にアクセスしてみよう。

サーバが出力したエラーページ

エラーメッセージが表示されたが、これは、まだコンテンツを返すプログラムを作っていないために表示されるもので、正常な動作である。アプリケーションを終了するには、出力ウィンドウの左側にあるStopボタンをクリックする。

8080ポートが使えない場合(演習室では使えない)はポート番号を変える必要がある。18080に変えるにはapplication.propertiesに次の1行を追加する。

何か表示してみる

Lect01Controllerクラスを作成して実行し、次のURLにアクセスしてみよう。

クラスの継承(まとめ)

継承とは

  • 継承するとメンバーを受け継ぐ(メンバーのアクセス修飾子に注意)
  • 継承の元となるクラス(親)は「スーパークラス」、継承によって作られた新しいクラス(子)は「サブクラス」
  • Javaの継承は「単一継承(親は1つだけ)」で、すべてのクラスの祖先となるのはObjectクラス(extendsを書かないクラスはextends Objectが省略されていると考えれば良い)。

(メンバーを受け継ぐことに加え)サブクラスでできること

  • メンバーを加えることができる(メンバーを加えない≒スーパークラスと同じ、なので加えないと意味がない)
  • 「super」でサブクラスからスーパークラスのメソッド(コンストラクタを含む)を呼び出すことができる
  • スーパークラスにあるメソッドをオーバーライド(上書き)することができる

継承の使い所

  • (なんらかの理由でクラスのメンバーの追加・修正ができない場合に)継承して機能を拡張する。
  • 共通部分をスーパークラスとしてまとめ、個別の機能をサブクラスで記述する(この用途には「抽象クラス(教科書P.114)」が適切な場合がある)
  • 同じように呼び出すことができるメソッドを持たせる(この用途には「インタフェース(教科書P.116)」が適切な場合がある)。
  • etc…

クラスの継承(2)

前回のまとめ

  • 継承するとメンバーを受け継ぐ
  • ただしメンバーのアクセス修飾子に注意
  • 継承の元となるクラスは「スーパークラス」、継承によって作られた新しいクラスは「サブクラス」
  • super: サブクラスからスーパークラスのメソッド(コンストラクタを含む)を呼び出すことができる
  • スーパークラスにあるメソッドをオーバーライド(上書き)することができる

サブクラスからスーパークラスへのキャスト

コード全体: Main1.java

サブクラスはスーパークラスのメンバーをすべて持っている。
よって、サブクラスのインスタンスはスーパークラスのインスタンスとみなしても(として扱っても)大丈夫だ。

実際に、次のようなコードが書ける。

これは、次のような状況だ。

サブクラスからスーパークラスへのキャスト

comicで使う場合はComicクラスのインスタンスとして扱うことができるが(当たり前)、comicAsBookで使う場合はBookクラスのメンバーしか使えない。つまり

は実行できるが、

はコンパイルエラーになる。

これができると何が嬉しいのだろうか?1つは「BookとComicを(Bookの情報だけになるが)同じように扱える」ということだ。前回は
BookとComicでそれぞれ配列を作ってデータを扱っていたが、まとめてBookの配列として扱うことができる。つまり、

とすることができる。ただし、bookList[1]は本来Comicだが、Book扱いになる。

Book扱いになる(つまりComicで追加されたメンバーは使えない)が、オーバーライドされたメソッドはどういう扱いになるのだろうか。
次の実行結果を確認しよう。

コメントにも書いてある通り、「どのクラスとして扱っているか」ではなく、「インスタンス化した時のクラス」の実装が使われる。

すべてのクラスはObjectクラスを継承している

コード全体: Magazine.java, Main2.java, Main3.java

雑誌を表すMagazineクラスを作ってみよう。

Objectクラス

オーバーライドする時にIDEを使うと、候補となるメソッドが表示されるが、Bookクラスで定義していないメソッドがあるのが確認できるはず。これはObjectクラスのメソッドである。
実は(Objectクラスを除く)すべてのクラスはObjectクラスを継承している。正確には「extends」で指定しない場合には、Objectクラスが自動的に継承される。
つまり「Objectを継承したBook」を継承しているのがMagazineという関係である。

すべてのクラスがObjectを継承しているのなら、Objectの配列は参照型ならすべて格納できる、ということになる。

toStringメソッド

ここでは、toStringメソッドをオーバーライドしてみよう。これにより、System.out.printlnの引数として指定した時に表示する文字列を指定することができる。

では、確認しよう。

instanceof演算子とスーパークラスからサブクラスへのキャスト

Object型のままだと、その中のインスタンスが何であってもできることが限られる。実際のインスタンスの型を判別してキャストしよう。型の判別にはinstanceof演算子(教科書P.126)を使う。instanceof演算子で、「指定した型にキャストできるか」を判断することができる。Bookクラスにキャストできる(つまりBookクラスかBookの子孫となるクラス)かどうか判別してCSVを出力してみよう。

equalsメソッド

参照型の比較には==が使えない場合が多い。比較が必要なクラスはObjectクラスのequalsメソッドをオーバーライドする、という慣例になっている(「慣例」と書いたが、多くのライブラリが前提としてるので、ほぼルールと言って良い)。
例えば、文字列の比較の例を見てみよう。

Magazineのequalsメソッドをオーバーライドしてみよう。

結果を確認しよう。

クラスの継承(1)

前回のまとめ

  • 型は大別してプリミティブ型と参照型の2つ。
  • プリミティブ型は「箱」のイメージでOK。代入は「値をコピー」
  • 参照型は「商品タグ」のイメージ。インスタンスを指し示すのがインスタンス名(変数名)。代入は「商品タグが同じところに繋がる(ポインターのコピー)」
  • プリミティブ型と参照型では、代入や比較等で(初学者にとって)直感的でない違いがあるので注意する。この違いはコードを実行して確かめること。
  • 文字列や配列は参照型。よく使われるので「特別扱い」されている(使いやすくなっている)。

クラスの継承

本を管理する

(書店を経営しているつもりになって、あるいは自分の蔵書について)本を管理するソフトを作ることを考えよう。まず、本(小説とか)を管理するクラスを作ろう。

このクラスを使った例を次に示す。

GitHubで見る:

「巻」を管理できるように拡張する

漫画などは「第1巻」、「第2巻」と、同じタイトルでシリーズになっているものが多い。この「巻」の管理はBookクラスではできないので新しくComicクラスを作ることを考えよう。ただし、1から新しく作るのではなく、Bookクラスを元に「巻」に関する情報が扱えるように拡張することを考える。

ポイント:

  • 3行目: 「extends Book」で「Bookクラスを継承する」という意味になる。
    • この場合、Bookクラスが「スーパークラス」、Comicクラスが「サブクラス」ととなる。
    • Bookクラスにあるメンバー(フィールドとメソッド)が引き継がれる(使える)。
    • アクセス修飾子(教科書P.170)によって違いがあるので注意する。
  • 4-7行目: Comicクラスだけで使えるフィールド
  • 9-14行目: Bookクラスとは違うコンストラクタにしたい(インスタンス化時に追加したフィールドに値をセットしたい)ので定義する
  • 11行目: superをメソッドのように使う(括弧をつけて引数を渡す)とスーパークラス(この場合Bookクラス)のコンストラクタが実行される。
  • 16-28行目: 巻の情報も出力したいので、getInfoCSVメソッドを上書き(オーバーライド)する。
  • 17行目: @Overrideアノテーション(教科書P.180)
  • 21,24行目: オーバーライドする前の元のメンバーを使いたい場合は、superに「.」をつけてアクセスする(thisと同じような感じ)。
  • 28-35行目: Comicクラスだけで使えるメソッド

このクラスを使った例を次に示す。

GitHubで見る:

プリミティブ型(基本型)と参照型(クラス型)

The types of the Java programming language are divided into two categories: primitive types and reference types.

Java言語の型は次の2つのカテゴリーに分けられる: プリミティブ型と参照形。

プリミティブ型(基本型)

次の8種類。整数はすべて符号付きで、C言語と違ってunsignedはない。

格納できる値 備考
boolean 真偽値(trueもしくはfalse)
char 1文字 Unicodeのコードを表す16ビットの整数。教科書P.12
byte 整数(8ビット) 教科書P.10
short 整数(16ビット) 教科書P.10
int 整数(16ビット) 教科書P.10
long 整数(32ビット) 教科書P.10
float 実数(32ビット) 教科書P.11
double 実数(64ビット) 教科書P.11

基本型の変数は、「箱」のイメージで問題ない。変数名は箱についている名前。

では、次のコードを実行してみよう(コード全体)。

(1)では、aに0、bに1を代入している。

(1) プリミティブ型の宣言と初期化

(2)で代入という操作をすると、aの値がコピーされてbに入る。

Primitive2

(3)で、aに代入するとaの値が変わる。bの値は変わらない。

Primitive3

参照型(クラス型)

参照型はクラス型ともいい、要するに、クラスによる型のこと。クラス型の変数は、クラス(やインターフェース)の実体(インスタンス)を格納する。

例えば、円(通貨じゃなくて図形の方)を表すCircleクラスを定義して、インスタンス化することを考えよう。半径を表すフィールドを持つクラスである。

この場合の変数は、プリミティブ型の時と違って、「箱」のイメージではない!「商品タグ」のイメージが適切である。特に代入演算子を使った時の処理について注意が必要だ。実際に実行して、代入がどのような操作なのか確認しよう。

(4)では、インスタンス化して、フィールドに値を代入している。変数名(インスタンス名)は商品タグのようにインスタンスに紐づいている。

(4) 参照型のインスタンス化とフィールドへの代入

(5)で、代入の操作を行っているが、これは「c2の紐付け先をc1のものと同じにする」という意味になる(C言語がわかっている人向けの説明: ポインタのコピー)。元々c2が紐づいていたインスタンスはどこからも使われていない状態になったので、ガベージコレクタ(教科書P.92)によって、そのうちメモリから消される。

Reference2

(6) c1のフィールドの値を代入によって変更すると、c2のフィールドも同じになる(というか同じものを指し示している)。

Reference3

このように、参照型では(初学者にとっては)直感と違う処理が行われるので注意する。この辺りについては「シャローコピー」や「ディープコピー」といった単語で検索してみると理解が深まるだろう。

比較

代入だけではなく、比較についても注意しなければならない。次のコードを実行して見よう(コード全体)。

参照型の比較は、「指し示しているインスタンスが同じか」という比較をしているので、フィールドの値がすべて同じであったとしても指し示しているインスタンスが違えばfalseとなる。参照型は、普通は「==」で比較してはいけない、と覚えておこう(もちろん、同じインスタンスを指し示しているか、という判別が必要なときはこれで良い)。

では、参照型で比較したい場合はどうしたらいいのだろうか?これは、地味にフィールドを比較していくしかない。Circleクラスの場合はフィールドが1つだけなので簡単だが、フィールドがたくさんある場合は大変だ。なので、比較が必要なクラスは比較するためのメソッドを作っておくのが良い。じゃあ、どうやって作るか、利用するか、ということは今後の講義で解説する。

参照型あれこれ

文字列

Javaの文字列はStringクラスのインスタンスだ。つまり参照型だ。だから、比較などでは注意しなければならない。また、文字列は非常によく使われるので、特別扱いされている。

特別扱い1: 普通のクラスはnew演算子でインスタンス化を行うが、文字列のインスタンス化はダブルクォーテーションで囲むことによってインスタンス化することができる!

ちなみに、ダブルクォーテーションを使わず、charの配列から文字列を作ると次のようになる。

特別扱い2: +演算子で結合ができる!(教科書P.13、ちなみに、「演算子のオーバーロード」という機能がある言語では、+演算子の機能を変えることができる)

Javaの文字列は様々なメソッドが用意されているので使ってみよう。

配列

配列も参照型である。

lengthという読み取り専用の特殊なフィールドのようなものがある(教科書P.23)。

例えば、for文でループ回数に使えば、文字列の長さが変わってもその部分のコードを書き換える必要はなくなる。