広告

■□■□■□■□■□■□■□■□■□■□■□■□■□■□■
                      2010年04月07日

    Java総合講座 - 初心者から達人へのパスポート
                  2009年11月開講コース 021号

                                セルゲイ・ランダウ
 バックナンバー: http://www.flsi.co.jp/Java_text/
■□■□■□■□■□■□■□■□■□■□■□■□■□■□■


-------------------------------------------------------
・現在、このメールマガジンは以下の2部構成になっています。
[1] 当初からのコース:毎週日曜の夜に発行
   これは現在、中級レベルになっています。
[2] 2009年11月開講コース:毎週水曜の夜に発行
   これは現在、初心者向けのレベルになっています。
・このメールマガジンは、画面を最大化して見てください。
小さな画面で見ていると、不適切な位置で行が切れてしまう
など、問題を起すことがあります。
・このメールマガジンに掲載されているソース・コード及び
文章は特に断らない限り、すべて筆者が著作権を所有してい
ます。また、これらのソース・コードは学習用のためだけに
提供しているものです。
-------------------------------------------------------


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
(2009年11月開講コース)021号
 当記事はvol.021のリバイバル(revival)版です。
 vol.021の内容を最新のEclipse、Javaに基づいて書き直しています。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━


========================================================
◆ 01.データベース
========================================================

オープン・ソースのRDBMSのうちで一番著名なものといえば、
MySQLとPostgreSQLがあげられると思いますが、世界的には特に、
MySQLの人気が高いですね。

MySQLはもともとは小規模のデータベース用というイメージがあった
のですが、最近では大規模データベースにも対応できるようになっ
てきているし、PostgreSQLよりも性能がよくて、かつ、使い方も簡単
という点でも人気があるようです。

そこで、当メールマガジンでもRDBMSとしてはMySQLを採用しようと
思っていたのですが・・・。


・・・、MySQLでコミット(commit)やロールバック(rollback)
を行うためにはストーレッジ・エンジン(データの読み書きを行う
ソフト)としてInnoDBかBerklayDB(ともにオープン・ソース)を
使用する必要があります。
実は、InnoDBもBerklayDBもMySQLとは別の会社が開発したものなの
ですが、どちらもOracle社に買収されました。

一方、MySQLのメーカーであるMySQL AB社は、Sun Microsystems社
に買収されました。

ところがつい先日には、今度はこのSun Microsystems社もOracle社に
買収されました。

Sun Microsystems社は言うまでもなくJavaを有する会社ですが、他に
主力製品であるコンピューター製品やOS、MySQLやOpenOffice.orgと
いったオープン・ソースなど数々のプロダクトを有していますが、
これらが一挙にOracle社のものになってしまったわけです。
これによってOracle社はソフトウエア会社からコンピューターの総合
メーカーへと一挙に拡大することになります。

Oracle社は有料のRDBMSの最大手のメーカーとして知られていますが、
この買収によって特にオープン・ソースのMySQLを所有してしまった
ことはオープン・ソースを利用する者にとっては不安要素となります。
つまり、MySQLをOracle社のRDBMSの販売戦略に都合のいいように改変
されてしまわないかという心配がありますが、これについてはOracle社
が「当分の間、オープン・ソースを維持する」ということを明言して
います。

とは言いながら、MySQLがこの先どうなるのか、やはり不安があります。


そこで取り上げたいのが、別のもっと使い方が簡単なオープン・ソースの
RDBMSです。

2005年末から開発が始まって、2006年に最初のバージョンがリリースされた、
まだ新しいRDBMSで、H2(H2 Database Engine)という名前のオープン・ソー
スです。
H2は、MySQLよりもさらに性能がよいことを標榜しているRDBMSであり、かつ、
インストールや使用方法もとても簡単です。
また、このRDBMS自体がJavaで作られているという点も、当メールマガジン
で取り上げることにした理由のひとつです。

初めてデータベースを使い始める人にとっては最適なRDBMSだと思います
ので、まずはこのRDBMSから使い始めることにしましょう。
(ただし、MySQLもそのうちに適切な時点で使用します。)

というわけで、今回は、H2 Database Engineをダウンロードしてインス
トールし、使用してみましょう。

まず、

(1) Webブラウザーで

http://www.h2database.com/

を開きます。

(2) Downloadという枠の中にある
「Windows Installer (4 MB) 」
というのをクリックします。

(3) 今までにJavaのJDKやEclipseをダウンロードしたときと同じ要領で
ファイルをダウンロードして保存しておきましょう。(保存する場所と
ファイル名を忘れないようにご注意を。忘れそうな人はメモしておきま
しょう。)

(4) ダウンロードして保存したファイル(h2-setup-2010-03-21.exeとい
うようなファイル名になっているはず)をダブル・クリックして実行し
ます。(読者が当記事を呼んでいる時点によっては、ファイル名が変わ
っている可能性がありますので、ご注意ください。)

┌補足─────────────────────────┐
「次の不明な発行元からのプログラムにこのコンピューター
への変更を許可しますか?」などのセキュリティー関係のメッ
セージが表示されたときは「はい」ボタンをクリックして先へ
進めてください。当メールマガジンではこういったセキュリ
ティー関係のメッセージについてはいちいち記述しませんが、
以後各自で判断して行って下さい。

もし、このファイル(h2-setup-2010-03-21.exe)が実行でき
ない(実行しようとするとエラーになる)場合は、ダウンロー
ドに失敗してファイルが破損している可能性もありますので、
再度(1)から繰り返してダウンロードをやり直してみてください。
└───────────────────────────┘

(5) 「インストール先を選んでください。」のウインドウが表示されたら、
(必要な人は自分でインストール先フォルダを変更し、そうでない人は
そのまま)「次へ」ボタンをクリックします。

(6) 次のページでもそのまま「インストール」ボタンをクリックしまし
ょう。

(7) 「完了」ボタンをクリックします。これで、インストールは完了で
す。

(8) Webブラウザーで「H2 Database Engine」のページが開いたら、閉じ
ておきましょう。

では、さっそくH2 Databaseを使ってみましょう。

(1) 「スタート」ボタンをクリックし、「すべてのプログラム」 ==> 「H2」
 ==> 「H2 Console」(Command Lineでない方)を選択しましょう。

(2) 「Login」のページ(Webページ)が開きますので、下のほうにある
「Connect」 ボタンをクリックしてください。
(英語が苦手な人はこの「Login」のページ上のEnglishを日本語に切り替える
こともできますが、当メールマガジンでは英語表示の状態で話を進めます。)

(3) H2のコンソール(Console)と呼ばれるページが開きます。コンソール
はH2にコマンド(命令)を送り込み、その結果やデータベースの状態を表示
させるための画面です。

このページの上のほうに
「Run (Ctrl+Enter)」と「Clear」というボタンがありますが、その下にある
広い枠の中にSQL文を入力して「Run (Ctrl+Enter)」ボタンをクリックすると
入力したSQL文がRDBMSに送り込まれ、命令が実行されます。

というわけで、前回説明したSQL文を入力して実行してみましょう。
まず
CREATE TABLE hotel (num INTEGER NOT NULL, name CHAR(50), address CHAR(80),
PRIMARY KEY (num))
を入力し、 「Run (Ctrl+Enter)」ボタンをクリックしましょう。
(なお、文の終わりを示すために、通常は文末にセミコロン(;)
を入れますが、1つの文だけならセミコロンがなくても大丈夫です。)

これで、hotelテーブルが作成されます。
画面の左側の「jdbc:h2:~/test」の文字列の下にHOTELの表示が出ますので、
hotelテーブルが実際に作成されたことがわかります。

続いて、いったん「Clear」ボタンをクリックしてSQL文を消したあと、
次の
INSERT INTO hotel  VALUES (1, '有名ホテル', '市川市なんとか町100-100-100')
を入力して「Run (Ctrl+Enter)」ボタンをクリックしましょう。
(入力時に適時、入力の支援機能が働いて、入力可能な文字列(テーブル名など)
のリストが表示されるときがありますが、このときはリストの中から選択すると
楽です。)

同様にして(先ほどのSQL文を書き換えて)
INSERT INTO hotel  VALUES (2, '無名ホテル', '市川市かんとか町200-200-200')
を実行してみましょう。

次に、
SELECT num, address FROM hotel WHERE name = '有名ホテル'
で、データを検索してみましょう。
検索結果がちゃんと表示されますね。

では、ついでに、
SELECT * FROM hotel
を実行してみましょう。
このSELECT文にはWHEREの指定がありませんので、hotelというテーブルの
中に入っているデータをすべて取り出すことを意味します。また、SELECTの
後ろの*はすべての列を取り出すことを意味します。

すべてのデータが表示されましたか?といってもデータは2行しかないですが、
これじゃ寂しいという人は、自分でINSERT文をどんどんと作成して、データを
追加していってみてください。

はい、では次にデータの更新(変更)をしてみましょう。
UPDATE hotel SET address = '船橋市かんとか町200-200-200'  WHERE num = 2
そして、再度
SELECT * FROM hotel
で全データを確認してみましょう。
「無名ホテル」のADDRESSが「船橋市かんとか町200-200-200」に変更されて
いることが確認できましたね。

では、データ(行)の削除を行ってみましょう。
DELETE FROM hotel WHERE num = 2
そして
SELECT * FROM hotel
を実行して再度全データを確認してみましょう。
「無名ホテル」が消えてしまいましたね。

余裕のある人はコミットやロールバックも試してみてください。
なお、画面の上にほうにある「Auto commit」にチェックマークが入っている
と自動的にコミット(COMMIT)がかかってしまいますので、ロールバック
(ROLLBACK)が有効に働きません。

コミットやロールバックのテストをしたいときは事前にこのチェックマーク
をはずしておいてから
INSERTやUPDATEやDELETEとCOMMITやROLLBACKを交互に試し、そのつどSELECTで
実際のデータの内容を確認してみてください。

では、最後にテーブルを削除してみましょう。
DROP TABLE hotel
これでhotelテーブルは無くなりました。テーブルがなくなったことは
左側の 「jdbc:h2:~/test」の下にあったHOTELの表示が消えたことでわ
かります。
また、実際にSELECT文などを実行してhotelテーブルから検索しようとすると、
エラーのメッセージが出ます。

では、このWebブラウザーは閉じておきましょう。
次回はRDBMSをJavaのプログラムから呼び出して使用する方法について
お話します。


========================================================
◆ 02.文法解説 [インターフェース型]
========================================================

Javaのインターフェース(interface)とは、オブジェクトの呼び出し方を
定義したものを言います。

具体的には、たとえば何らかの音楽の演奏家を表すオブジェクトを定義し
たい時には、そのメソッドを以下のようにinterfaceというキーワードを指定
して定義します。メソッドの他にstaticな固定値のフィールドも定義でき
ます。外部から呼び出せるものに限りますので、メソッドもフィールドも
すべてpublic指定になります。なお、メソッドにはstaticの指定はできま
せん。

public interface MusicPlayer {
   public static final String name = "Music Player";
   public void play();
   public void stop();
   public void setVolume(int volume);
}

これはあくまでオブジェクトの呼び出し方を定義したものに過ぎず、たとえば
上のplay()、stop()、setVolume()のメソッドが実装(プログラミング)されて
いるわけではありません。

このインターフェースというものはいったい何がありがたいかというと、実際
の実装をしていない段階からそのオブジェクトを呼び出して利用するプログラム
を書けるということなんですね。たとえば、以下のようなコンサートのクラスを
考えましょう。

public class SoloConcert {
   private MusicPlayer player;
   public void setPlayer(MusicPlayer aPlayer) {
      player = aPlayer;
   }
   public void play() {
      player.play();
   }
   public void stop() {
      player.stop();
   }
}

このコンサートでは、どんな演奏家が出演するかまだ決まっていない段階でも
プログラムが作れてしまうのです。上記のSoloConcertというクラスの中で使われ
ているMusicPlayerは上で定義したインターフェースであってクラスではありませ
ん。このMusicPlayerは実際には、まだ実装されていないのです(実装されていて
もかまいませんが実装されていなくてもかまいません)。
つまりSoloConcertクラスは、MusicPlayerの実装とは独立してプログラミングでき
るわけです。

一方、MusicPlayerを実装する側は、SoloConcertとは独立して実装することがで
きます。たとえばフルートの演奏家を定義するとしましょう。

実際の実装は、クラスを定義して行う必要があり、たとえば

public class FlutePlayer implements MusicPlayer {
   private int soundVolume = 0;
   public void play() {
      // 音楽の演奏の実装。
   }

   public void setVolume(int volume) {
      soundVolume = volume;
   }

   public void stop() {
      // 音楽の演奏を停止する実装。
   }
}

というようにclass文の中の「implements インターフェース名」によって、
実装したいインターフェースを指定し、そのメソッドを実装します。(上記の
クラス定義では実際の実装は省略し、代わりにコメント文を入れています。)

こうしておけば、このFlutePlayerはMusicPlayerの一種として扱われ、
SoloConcertのsetPlayer()メソッドでSoloConcertにセットして呼び出す
ことができます。
その他、ピアノの演奏家でもギターの演奏家でも何でもMusicPlayerを実装
したクラスであればSoloConcertのsetPlayer()メソッドでSoloConcertにセット
して呼び出すことができます。そしてフルート演奏家もピアノ演奏家もギター
演奏家もそれぞれが独立した人格(実装)を持つことができます。

クラスの継承に似ていますが、違うところはinterfaceは実装をせず、呼び
出し方(何という名前のメソッドを持ち、どんな引数と戻り値を持っている
か)だけを指定したものであることと、実装する側のクラスは複数のインター
フェースを実装できる点です(後述)。

このように、クラスを実装する側とそれを呼び出す側の間で、開発の前に
その呼び出し方を取り決めておいて、それをJavaのインターフェースで定義
しておけば、両者が独立に開発を続けていくことができます。

そして、先ほどのSoloConcertクラスの中の
private MusicPlayer player;
で宣言したplayerという変数は、MusicPlayerというインターフェースの型を
持つので、このような変数はインターフェース型と呼ばれます。



======================================================
◆ 03.前回の演習問題の答
======================================================

1次元の配列のほうは予期した通りの結果になるが、2次元の配列
のほうは意外な結果になったと感じたのではないでしょうか。
つまり、2次元の配列では、

int [][] gClone = g.clone();
gClone[1][1] = 50000;

というようにクローン(複製)のほうにだけ50000という値を設定
したはずなのに結果を見ると、

・・・(中略)・・・
・・・(中略)・・・
gClone[1][1] = 50000
・・・(中略)・・・
g[1][1] = 50000
・・・(中略)・・・

というふうにクローンのgClone[1][1]だけでなく、元のg[1][1]にも
50000という値がはいっていますね。


これは実は、2次元の配列が1次元の配列の参照を要素として持つ1次元の
配列として作られているからです。つまり、1次元の配列の要素が1次元
の配列になっているという、いわば1次元の配列を複数階層的に組み合わ
せた構造になっているのです。・・・と文で説明してもわかりにくい
と思うので、Javaのソース・コードで表現してみましょう。

つまり、2次元の配列

int [][] g = new  int[][] {{1, 2, 3}, {4, 5, 6}};

あるいは、

int [][] g = new  int[2][3];
g[0][0] = 1;
g[0][1] = 2;
g[0][2] = 3;
g[1][0] = 4;
g[1][1] = 5;
g[1][2] = 6;

は、

int [][] g = new  int[2][3];
int [] a1 = new int[3];
a1[0] = 1;
a1[1] = 2;
a1[2] = 3;
int [] a2 = new int[3];
a2[0] = 4;
a2[1] = 5;
a2[2] = 6;
g[0] = a1;
g[1] = a2;

というふうにして作った配列gと同じなのです。
このような構造になっていることは、g.lengthの値などを調べても
わかると思います。

(3次元以上の配列も同様に1次元の配列を複数階層的に組み合わ
せた構造になっています。)


そして、

int [][] gClone = g.clone();

を実行すると、gCloneという新しい配列が作られると同時にgCloneの各要素には
gの各要素の値のコピーが代入され、つまり、

gClone[0] = g[0]の値のコピー;
gClone[1] = g[1]の値のコピー;

が実行されることになります。

ここでg[0]の値やg[1]の値はa1やa2という配列のアドレス(参照)であり、
それらのコピーはやはり同じ配列のアドレス(参照)となります。

そして、アドレスのコピーも結局は元のアドレスと同じオブジェクトを
参照しますから、元のa1やa2というオブジェクトを参照するのです。

すると、gClone[1][1]は、gClone[1]すなわちa2の2つ目の要素すなわち
a2[1]の値を参照することになりますから、gClone[1][1]に50000を代入
するとa2[1]に50000が代入されることになり、そうすると元のg[1][1]の
値を調べても(これもa2[1]ですから)50000が得られることになります。



下記のようなクラスを作成して確認してみて下さい。

-------------------------------------------------------
package jp.co.flsi.lecture.human;

public class ArrayTest2 {

   public static void main(String[] args) {
      int [][] g = new  int[2][3];
      g[0][0] = 1;
      g[0][1] = 2;
      g[0][2] = 3;
      g[1][0] = 4;
      g[1][1] = 5;
      g[1][2] = 6;
      int [][] g1 = new  int[2][3];
      int [] a1 = new int[3];
      a1[0] = 1;
      a1[1] = 2;
      a1[2] = 3;
      int [] a2 = new int[3];
      a2[0] = 4;
      a2[1] = 5;
      a2[2] = 6;
      g1[0] = a1;
      g1[1] = a2;

      System.out.println("g[0][0] : " + g[0][0]);
      System.out.println("g[0][1] : " + g[0][1]);
      System.out.println("g[0][2] : " + g[0][2]);
      System.out.println("g[1][0] : " + g[1][0]);
      System.out.println("g[1][1] : " + g[1][1]);
      System.out.println("g[1][2] : " + g[1][2]);
      System.out.println("g1[0][0] = " + g1[0][0]);
      System.out.println("g1[0][1] = " + g1[0][1]);
      System.out.println("g1[0][2] = " + g1[0][2]);
      System.out.println("g1[1][0] = " + g1[1][0]);
      System.out.println("g1[1][1] = " + g1[1][1]);
      System.out.println("g1[1][2] = " + g1[1][2]);
      int [][] gClone = g1.clone();
      int [][] gClone2 = g1.clone();
      gClone2[0] = a1.clone();
      gClone2[1] = a2.clone();
      gClone[1][1] = 50000;
      System.out.println("gClone.length = " + gClone.length);
      System.out.println("gClone[0].length = " + gClone[0].length);
      System.out.println("gClone[0][0] = " + gClone[0][0]);
      System.out.println("gClone[0][1] = " + gClone[0][1]);
      System.out.println("gClone[0][2] = " + gClone[0][2]);
      System.out.println("gClone[1][0] = " + gClone[1][0]);
      System.out.println("gClone[1][1] = " + gClone[1][1]);
      System.out.println("gClone[1][2] = " + gClone[1][2]);
      System.out.println("g1.length = " + g1.length);
      System.out.println("g1[0].length = " + g1[0].length);
      System.out.println("g1[0][0] = " + g1[0][0]);
      System.out.println("g1[0][1] = " + g1[0][1]);
      System.out.println("g1[0][2] = " + g1[0][2]);
      System.out.println("g1[1][0] = " + g1[1][0]);
      System.out.println("g1[1][1] = " + g1[1][1]);
      System.out.println("g1[1][2] = " + g1[1][2]);
      gClone2[1][1] = -5;
      System.out.println("gClone2.length = " + gClone2.length);
      System.out.println("gClone2[0].length = " + gClone2[0].length);
      System.out.println("gClone2[0][0] = " + gClone2[0][0]);
      System.out.println("gClone2[0][1] = " + gClone2[0][1]);
      System.out.println("gClone2[0][2] = " + gClone2[0][2]);
      System.out.println("gClone2[1][0] = " + gClone2[1][0]);
      System.out.println("gClone2[1][1] = " + gClone2[1][1]);
      System.out.println("gClone2[1][2] = " + gClone2[1][2]);
      System.out.println("g1.length = " + g1.length);
      System.out.println("g1[0].length = " + g1[0].length);
      System.out.println("g1[0][0] = " + g1[0][0]);
      System.out.println("g1[0][1] = " + g1[0][1]);
      System.out.println("g1[0][2] = " + g1[0][2]);
      System.out.println("g1[1][0] = " + g1[1][0]);
      System.out.println("g1[1][1] = " + g1[1][1]);
      System.out.println("g1[1][2] = " + g1[1][2]);
   }

}
-------------------------------------------------------



◆編集後記◆━━━━━━━━━━━━━━━━━━━━━━━━

☆☆☆騙されないようにしよう!☆☆☆
 最近、インターネットで(価値のない)情報商材を高く売って儲けよ
 うとする輩が増えているようです(価格は数千円〜数万円程度の
 ようですが、人によっては安いと感じるかも知れません)。この種
 の販売のテクニックが流通しており、たとえば販売のWebページには
 読者を信用させるために、購入者の感想文やコメント(実は偽造し
 たもの)をたくさん掲載するとか、「気に入らなければ返金します」
 と明記するといったものがあり(購入者が心理的に返金を請求し
 にくいことを悪用し、また、元々コストがゼロなので返金しても損失
 がない)、巧みな文章に騙される人も少なくないようです。また、キャ
 ンペーンなどの形で期限を切ることによって、Webページの読者があ
 せって購入するようにしむけるのも一つのテクニックのようです。
 メールマガジンやブログなどを利用して盛んに集客を行っているよう
 ですが、合法的に見えるように体裁を整えていて、騙されたと感じて
 も訴えることが難しいものが少なくないようです。
 Javaとは関係ありませんが、インターネット上には信用できない情報
 もたくさん流されているということを意識し、ずる賢い商売やサギに騙
 されないように十分ご注意ください。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      http://www.flsi.co.jp/Java_text/
★このメールマガジンは
     「まぐまぐ(http://www.mag2.com)」
 を利用して発行しています。
★バックナンバーは
      http://www.flsi.co.jp/Java_text/
 にあります。
★このメールマガジンの登録/解除は下記Webページでできます。
      http://www.mag2.com/m/0000193915.html
★このメールマガジンへの質問は下記Webページにて受け付けて
 います。わからない所がありましたら、どしどしと質問をお寄
 せください。
      http://www.flsi.co.jp/Java_text/
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Copyright (C) 2010 Future Lifestyle Inc. 不許無断複製