導入
前回からオブジェクト指向の学習に入り、インスタンスを作らないで使えるクラスの便利さを学びました。今回はインスタンスを作って使うクラスの便利さの例を紹介します。プログラミングの学習は、いかに楽をするかを追求することだと思います。ある課題について楽にこなす技術があれば、より難しい課題に取り組むことが可能になります。積極的に楽をする方法を学びましょう。
展開
配列の扱いを便利にするArrayListクラス
この連載中で紹介した便利なクラスの代表はArrayListです。ArrayListは配列を便利に取り扱えるような工夫が詰め込まれたクラスです。ArrayListを使う最も大きなメリットは、要素数を実行時に自在に変更できることです。取り扱うデータの量があらかじめ分からない場合、配列を使うならば、予想される最大限の領域を確保しておくことになります。必要なければその領域を使わないか、実行時に要素数を指定するコードを書くことになります。
コード例を示します。もし、同じ配列名で要素数を変更する必要が生じると、これだけ面倒だということと、ほぼ同じことをArrayListですればこんなに楽だということを感じてください。
[注意] 配列のコピーは配列クラスのclone
メソッドやarraycopy
メソッド、System.arraycopy
メソッドがありますが、これらは各要素への参照をコピーするもので、コピー元の要素の値を変更すると、コピー先の値もそれに追随して変わります。このようなコピーをシャロー・コピー(Shallow Copy)と呼びます。
これに対してサンプルsketchのようにfor文で地道に代入する方法をディープ・コピー(Deep Copy)と呼びます。これは、コピー先の配列に対して元の配列の値を代入していますから、元の配列の要素の値を変更しても、コピー先の配列の要素の値は変化しません。
この違いは多次元配列のコピーで顕在化します。1次元配列のコピーではclone
もarraycopy
もディープコピーされることを筆者は確かめています。
[作業]1次元配列と2次元配列を作成し、それぞれclone
やarraycopy
でコピーしてください。そして、元の配列の要素の値を変更し、コピー先の配列の要素の値がそれに追随して変わることを確認しましょう。
ファイル入出力を楽にするPrintWriterクラスとBufferedReaderクラス
Processingでテキストデータをまとめて読み書きする分にはloadStrings
やsaveStrings
といったメソッドを使うのが一番です。
しかし、これらのメソッドは入力があるたびに保存、必要に応じて一行ずつ読み出しといった動作が必要な場合に対応しません。そのような場合には、PrintWriter
クラスやBufferedReader
クラスのインスタンスを用います。
ProcessingのAPIリファレンスを参照してください。
これらの便利なクラスを用いれば、ファイルの入出力が簡単に、そして安全に実行できます。それぞれのリファレンスに掲載されているサンプルを参照しましょう。注意点は、例外処理を記述する必要があることです。せっかくProcessingを使っているのですから、例外処理に煩わされたくありませんが、これらのクラスを使う場合は仕方ありません。
サンプルコードを読むと分かるように、これらのクラスを利用することで、データが発生するごとにファイルに記録するといった操作が可能になります。すべてのデータをプログラムが最後まで保持しておこうとすると、大変なメモリ容量が必要な場合があるでしょう。メモリを食いつぶしてソフトがクラッシュするという事態を防ぐことができます。短所として考えられるのは、データが発生する度に保存しますから、動作速度に影響があるでしょう。ファイルアクセスはソフトウエアの中で負荷の大きい処理の代表です。メモリに余裕があるか、それほど大容量のデータを取り扱わないならば、まとめて読み込み・書き込みを行うのも選択肢です。
演習
演習1(難易度:easy)
ArrayList
インスタンスのコピーにおいて、シャロー・コピーやディープ・コピーといった違いは起こるのでしょうか。調査してまとめてください。
演習2(難易度:easy)
PrintWriterとBufferedReaderそれぞれのリファレンスに掲載されているサンプルコードを連結しましょう。ディスプレイウインドウ上を動くマウスポインタの軌跡を黒い点として描画し、座標値を記録したテキストファイルを作成します。何かキーが押されたら記録を中断・終了します。座標が保存されたテキストファイルを読み込み、ディスプレイウインドウに赤い点を描き移動軌跡を再現してください。ファイル名はSaveAndLoad.pde
としてください。
まとめ
- インスタンスを作成して使うクラスの便利さを紹介しました。
学習の確認
それぞれの項目で、Aを選択できなければ、本文や演習にもう一度取り組みましょう。
ArrayList
クラスを使うと楽になる意味が理解できましたか?
- 理解できた。気持ちよく納得した。
- 理解できた。しかし、今ひとつスッキリしない。
- 理解できない。
ファイル操作用のクラスの便利さが理解できましたか?
- 理解できた。気持ちよく納得した。
- 理解できた。しかし、今ひとつスッキリしない。
- 理解できない。
参考文献
- 『本格学習Java入門[改訂新版]』(佐々木整 著、技術評論社)
- Java言語の基本的な文法が良くまとめられています。また、大変広い範囲をカバーしているので、はじめてJava言語に触る方が、Javaがどんな言語なのかを知るために役立つ資料になるでしょう。
演習解答
違いが起こる。
次のsketchを実行すると分かります。値を格納しているインスタンスはnames
です。インスタンスprogrammers
はnames
への参照を持っているだけで、programmers
だけのための記憶領域は確保していません。11行目でインスタンスnames
のアドレスを受け取っていると考えてください。このようなコピーでは、names
の要素への変更はprogrammers
の要素に影響し、逆もまた然りです。値を記憶している領域を共有しているのですから当然です。
ぞれぞれ独立した記憶領域を持つArrayList
インスタンスにしたければ、次のように操作する必要があります。新しく宣言したArrayList
インスタンスへコピー元のインスタンスの要素値を追加するのです。こうすることでnames
とprogrammers
でそれぞれ別の記憶領域に値を記憶させておくことができます。一方に加えた変更は他方へ影響を与えません。
SaveAndLoad.pde