07. Javaでオブジェクト指向(2/x)

2017年度資料

サウンド再生コードによる配列処理の演習(先週の続き)

HelloWorld.java を実行して動作確認する。

先回のページに作成例が添付されているのでダウンロードして利用OK。

配列処理の練習のため、以下の応用課題に取り組む。

応用:

サウンドデータ生成部分の修正

例)

・音声データバッファ buf 配列のサイズを変更 44100 → 22050 再生時間は半分になる。

・データ生成式の変更

i % 256 -128

この式は、ノコギリ波になる。

% は剰余計算記号。

モノラルの8bitサウンドフォーマットにするため、データは +127~-128 のバイト値に収まるように調整

i/2 % 256 -128

にすると、1オクターブ下の音になる。

i*2 % 256 -128

にすると、1オクターブ上の音になる。

i*2 % 256 -128

数学 と 音楽 の実験:

/2 や *2 の範囲(1/2倍 ~ 2倍 の範囲)で、5/4のミ と 3/2 のソを組み合わせて

*1/2 *9/16 *5/8 *2/3 *3/4 *5/6 *15/16 *1 *9/8(3/2 * 3/2 *1/2) *5/4 *4/3(2/3 * 2) *3/2 *5/3(2/3 * 5/4 *2) *15/8(3/2 * 5/4) *2

ド レ ミ ファ ソ ラ シ ド レ ミ ファ ソ ラ シ ド

などの単純な整数による比率を上の式で使用すると、純正律による ド ミ ファ ソ な音程を作成することができる。

ドレミファソラシド の音程用の比率 を 純正律について調べて利用してみよう。

参照)純正率と平均律の違いを体感しよう

課題1

eclipse で、 プロジェクト java1 を新規作成する。

音楽演奏プログラムの作成1:

SoundTestクラスを新規作成。

前回制作のHelloWorld クラスから、サウンド再生に必要な部分をコピペして組み込む。

※ mainメソッド内の該当コードを貼り付けると 必要に応じて import 文が追加される。

・ドレミファソラシド の8音のサウンドデータを初期化し、順番に再生する。

8音階用サウンドバッファを2次元配列で用意する。

byte[][] buf = new byte[8][44100];

ドレミファ~ でサウンドバッファを初期化する。

for (int i = 0; i < buf[0].length; i++) {

buf[0][i] = (byte) (i*1/2 % 256 - 128);

}

line.write に演奏する順番に配列を書き込むことで音階の再生する。再生時間を徐々に短くする。

line.write(buf[0], 0, buf[0].length);

line.write(buf[1], 0, buf[1].length/2);

line.write(buf[2], 0, buf[2].length/3);

line.write(buf[3], 0, buf[3].length/4);

line.write(buf[4], 0, buf[4].length/5);

line.write(buf[5], 0, buf[5].length/6);

line.write(buf[6], 0, buf[6].length/7);

line.write(buf[7], 0, buf[7].length/8);


line.drain();

※再生データが多くなり、lineにデータを書き込んでも、一度に再生されなくなる場合がある。

※対策として、 line.drain() を使用し、バッファに残っている全てのデータを強制出力する。

音楽演奏プログラムの作成2:

SoundTestクラスをコピペして、SoundTest2クラス を作成する。

※ファイル名やクラス名は自動的に修正される。

修正内容:

・2重ループと調律用の比率の配列を用いて、8音階を初期化する。

int[][] rate = { { 1, 2 }, { 9, 16 }, { 5, 8 }, { 2, 3 }, { 3, 4 }, { 5, 6 }, { 15, 16 }, { 1, 1 } };

for (int j = 0; j < buf.length; j++) {

for (int i = 0; i < buf[0].length; i++) {

buf[j][i] = (byte) (i * rate[j][0] / rate[j][1] % 256 - 128);

}

}

・演奏用データを配列で用意する。

int[][] score = { { 0, 2 }, { 1, 2 }, { 2, 2 },

{ 1, 2 }, { 2, 2 }, { 3, 2 },

{ 0, 4 }, { 1, 4 }, { 2, 4 },{ 3, 4 }, { 4, 4 }, { 5, 4 },{ 6, 4 }, { 7, 4 }};

・メロディー配列を参照してサウンドバッファから音声データを選択し、line に書き込むループ処理をする。

for (int i = 0; i < score.length; i++) {

line.write( buf[ score[i][0] ] , 0, buf[0].length / score[i][1]);

}

余技: ドレミファソラシドをテンポアップしながら繰り返し再生する。

for (int j = 0; j < 8; j++) {

for (int i = 0; i < 8; i++) {

line.write(buf[i], 0, buf[0].length / (i + 1)/(j+1));

}

}

課題提出について:

eclipseのワークプレイスのフォルダを zip 圧縮して、後日、他の回の課題と一緒にまとめて webclass に課題提出。

時間が余ったら、↓の2016年度課題にも取り組む。

以下、2016年度用資料

・出席はWebClass で登録。

作業メモ: 課題1,2,3の例を作成して添付する。

先週の続き)

Maze3の解説。

課題3の解説。 第6回 L6b と L6_1b

キーワード:

クラス継承、抽象化(アブストラクト)、インターフェース

講義資料:

(参考1) WebClass の 全学共通コース → Java入門 → 第6章(クラス)第7章(クラス継承)

↑ Javaの文法的な部分についてはこちらのテキストで確認できます(Webにも多数の解説サイトあり)。 オブジェクト指向としての例はちょっと微妙(Webにもなかなか良い例示が少ない)。

(参考2) 応用プログラミング1 の 第8回 オブジェクト指向2 を参照。

※資料を置いているサーバーが老朽化して、ところどこリンク切れになっています。

http://kaz.cyteen.nagoya-bunri.a.jp/ の部分を http://www.nagoya-bunri.ac.jp/~kobashi/ に置き換えると表示できます。

(参考3) ScratchでJava (クラス・インスタンス・メソッドの部分)

プロジェクト名 Project4

以下の問題1~問題7は、 ファイル L7_1.java に指定したクラスやメソッドを追加修正して作成するとよい。

※プロジェクト内のファイルは一括してコンパイルされる。同一のプロジェクト内で、別々のファイルで同一のclass名が存在すると、コンパイル時にエラーになる。

問題1

コンソールアプリケーションで、メッセージ(文字列)でキャラクターの行動を表現する

例)

public class L7_1 {   public static void main(String[] args) {   Cat mycat = new Cat(); // インスタンス生成   mycat.name = "クロ"; // インスタンス変数への書き込み      mycat.walk(100); // インスタンスメソッドの呼び出し   mycat.walk(10);   mycat.walk(1);   mycat.run(10);      Cat.sound(); // スタティックメソッドの呼び出し    // スタティック変数へのアクセス   System.out.println( Cat.limb + "本足");  }  }      class Cat {  String name;    static int limb = 4; //足の数    static void sound() {   System.out.println("みゃ~");  }    void walk(int step ) {      // ねこが step 歩く      System.out.println(name + "が" + step + "歩移動した");  }    void run(int step ) {      // ねこが step 歩く      System.out.println("ねこが" + step*10 + "歩 走る");  } }

↑のプログラムに コンストラクタ を追加して、name に初期値を与える様にする。 mainも修正する。

Cat(String name) {

this.name = name;

}

default コンストラクタを修正して、 new Cat() でインスタンスを生成した際には、name を ”名無し”となる様にする。

Cat() {
 //名前が "名無し" になるようなコードをここに書く
}

↑のプログラムに ねこ の現在の座標を管理する インスタンス変数 x y を追加して、移動するたびに値を更新するようにする。 mainも修正する。

int x;
int y;

値の更新の例) x += 10;

注) walk と run の両方とも座標の修正に対応すること。

↑のプログラムに report() メソッドを追加し、現在の座標を報告(コンソールに出力)するようにする。 mainも修正する。

void report() {

System.out.println( インスタンス変数 + "は X=" + インスタンス変数 + "にいる");

}

x,y 座標の報告でもよいし、 x 座標のみの報告でもよい。

↑のプログラムで、 sound(String str) のようにsoundメソッドをオーバーロードして追加し、 引数 str でコンソールで台詞を喋らせる。 mainも修正する。

(略)

問題2

2匹の猫が行動するように、 mainメソッドを修正する。適当に新しい猫の名前を決めて、コンソールに登場させる。

Cat yourCat = new Cat();

yourCat.name = "シロ";

yourCat.walk(50);

mycat.walk(10);

問題3

Cat クラスを元にして、より抽象度の高い Animal クラスを作成する。

Cat クラスを Animal クラスのサブクラスに修正する。

Animal クラスでは、動物のサイズ 大・中・小 と 名前 をフィールドに持ち、サブクラスに継承させる。

サイズの指定には、enum 列挙型 を使用する。 参照: http://www.atmarkit.co.jp/ait/articles/1103/03/news107_2.html

enum Size {
    Big, Medium, Small 
}

抽象メソッド move() を定義する。

abstract void move();

具体的な移動方法については、サブクラスで実装する。

コンストラクタを定義し、

abstract class Animal {
    String name;
    Size size;
    
    abstract void move();
    Animal(String name, Size size) {
        初期化のコードを書く
    }
}

注) super()super(String name, Size size) を使用して、Catのコンストラクタの修正が必要。

問題4

猫に鈴などのアイテムを付けるインターフェースを実装する。猫はアイテムを1つだけ装備できるとする。

インターフェース

interface ItemOwner {
        void attachItem(String item); // アイテムの装備

void dropItem(); // アイテムを捨てる

void useItem(); // アイテムを使う

}

ItemOwner を実装する側のクラスにフィールド String item を追加する。

この item 変数にアイテムを保持するためのコードをインターフェースのattachItemメソッドに書く。

他の2つのメソッドでは、○○を捨てました、○○を使いましたと、メッセージ表示するコードを書く。

各メソッドの実行内容は、それらしいメッセージを表示できればOK。 特に useItem についてはどのようなアイテムを持っているか判定して

使い方を変える必要はない。(次回 オブジェクト指向的 な解決方法を示す)

問題5

Crow クラスを、猫同様に設計する。カラスらしいメソッドを考え定義すること。

Crowクラスも、 ItemOwner クラスを実装すること。

問題6

Cat クラスに ランダムに移動する randomWalk() メソッド ランダムな歩数 x 座標 y 座標を移動。

ItemOwner インターフェースに、randomUse() メソッド アイテムの使用メッセージをランダム選択

を追加して、mainクラスにも修正を加える。

randomUse() のコードは難しそう。パスしてもOK。

アイテムを複数登録して利用するためには ↓

String item フィールドにはアイテムを文字列として、 1つだけしか登録できない。
アイテムを複数登録するためには、 String[] items のように複数のアイテムを登録するためのデータ構造を使う必要がある。
ArrayList<String> items の利用を推奨する。 ArrayList の利用方法を検索して調べてみよう。

問題7

Cat クラスの run を walk を利用するコードに変更する。mainクラスにも修正を加える。

例) walk を run の引数の回数実行するように変更する

応用:

・Animal の name フィールドを private に設定し、 setName(String name) など、アクセサー・メソッド を利用する様に修正する。

・ setName(int id_number) や setName(Object obj) など、メソッドを多重定義して、利用例を示す。

・setName( obj.toString() ) のように、オブジェクトの toString() メソッドを利用する例として、適当に自作 class と その toString メソッドの実装を考えて、使用例を示す。

例) Class RBGColor RGBの8bitカラーをインスタンス変数に保持する。 toString は、RGBカラーの HTMLでも文字表現 #808080 などを String で返すものとする。

次回解説予定。

・ItemOwer インターフェースの配列を作成し、幾つかの要素を持たせる。

拡張 for で全要素に同じアイテムを持たせ、使用させ、捨てさせる。

次回解説予定。

・猫がアイテムを持っていない場合、既に持っている場合についてメッセージを表示する様に、実装を修正。

インターフェースのメソッドの戻り値が void であるのを、 boolean に変更し、アイテム操作に成功した場合 true 失敗した場合 false を返すように変更する。

・猫が複数のアイテムを持てるようにインターフェースを設計

(説明略) 次回解説予定。

・Itemの使い方を、Itemの種類に応じて変えられるように Item クラスを作成して対応する。

(説明略) 次回解説予定。

・タートルグラフィックスシステムの制作

Java Applet 画面上に、タートルグラフィックスを描く ねこクラスを作成する。

グラフィックスの描画には、アニメーション処理 は付けなくてよい。

例えば、猫が、直進 100 右回転90 直進 100 右回転90 直進 100 右回転90 直進 100 右回転90 と動いた場合、画面には サイズ100の正方形が表示されるようにすること。

(ヒント)

ねこ クラス に命令された内容を記憶する commands クラス 配列を持たせる。

ねこ クラス に commands クラス配列 の内容に応じでグラフィックスを描画する、 execute() メソッドを作成する。