広告 |
---|
■□■□■□■□■□■□■□■□■□■□■□■□■□■□■ 2010年05月12日 Java総合講座 - 初心者から達人へのパスポート 2009年11月開講コース 026号 セルゲイ・ランダウ バックナンバー: http://www.flsi.co.jp/Java_text/ ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■ ------------------------------------------------------- ・現在、このメールマガジンは以下の2部構成になっています。 [1] 当初からのコース:毎週日曜の夜に発行 これは現在、中級レベルになっています。 [2] 2009年11月開講コース:毎週水曜の夜に発行 これは現在、初心者向けのレベルになっています。 ・このメールマガジンは、画面を最大化して見てください。 小さな画面で見ていると、不適切な位置で行が切れてしまう など、問題を起すことがあります。 ・このメールマガジンに掲載されているソース・コード及び 文章は特に断らない限り、すべて筆者が著作権を所有してい ます。また、これらのソース・コードは学習用のためだけに 提供しているものです。 ------------------------------------------------------- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ (2009年11月開講コース)026号 当記事はvol.027のリバイバル(revival)版です。 vol.027の内容を最新のEclipse、Javaに基づいて書き直しています。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ======================================================== ◆ 01.データベース(続き) ======================================================== 例として、人事管理用のデータベースを考えることにします。 (ただし、説明しやすくするために、かなり単純化します。) このデータベースには社員の情報、社員が所属する部門の情報、 社員の職位の情報などが含まれます。 まず、社員の情報を持たせるテーブルをEMPLOYEEという名前で 用意することにします。 EMPLOYEEテーブルには、以下のようなカラムを持たせます。 --------------------------------------------------- [EMPLOYEEテーブルのカラム] 社員番号、氏名、生年月日、所属部門、オフィス所在地 --------------------------------------------------- たとえば、その具体的なデータは以下のような感じになります。 --------------------------------------------------- 00001、舟木和子、1970年11月12日、総務課、Xビル2階 00002、安部泰三、1960年10月12日、総務課、Xビル2階 00003、長内順平、1986年08月12日、営業課、Xビル1階 --------------------------------------------------- なお、これらのカラムのうち、社員番号が特定の社員をユニー クに識別する(同姓同名の社員がいても社員番号を使えば確実 に特定の社員を識別できる)ものですから、社員番号を主キー にすることになります。一般に主キーには名前よりも番号を指定 することが望ましいです。 オブジェクト指向的に考えると、このEMPLOYEEテーブルは社員の クラスを表現するものと考えることもでき、各カラムはオブジェ クトの属性を表し、各行がそのクラスのインスタンスを表すもの と考えることができます。 (ただし、メソッドを表すものはテーブルの中にはありません。) このうち、所属部門とオフィス所在地というカラムに注目してく ださい。 所属部門には総務課や営業課などさまざまな部門がありますが、 これらは本来、社員の属性ではなく、社員とは別のオブジェクト と考えられますね。 (逆に各部門が何人かの社員を含んでいるわけで、一種の複合オ ブジェクトと考えることができます。) また、オフィス所在地も社員の属性ではなく、部門の属性と考え られます。 そこで、部門のオブジェクトを表すものとして下記のようなカラ ムを持つ別のテーブルを用意することにします。 テーブル名はDEPARTMENTとしておきましょう。 --------------------------------------------------- [DEPARTMENTテーブルのカラム] 部門コード、部門名、オフィス所在地 --------------------------------------------------- たとえば、その具体的なデータは以下のような感じになります。 --------------------------------------------------- 001、総務課、Xビル2階 002、営業課、Xビル1階 --------------------------------------------------- 主キーには部門コードを指定します。 そうすると、EMPLOYEEテーブルの所属部門カラムには部門名では なく部門コードを指定したほうが望ましくなります。 たとえば、企業が発展して営業課が大きくなり営業1課と営業2課に 分離することになったとし、営業1課の部門コードは営業課の時代の 002を引き継ぎ、営業2課の部門コードは003にしたとします。 もしEMPLOYEEテーブルの所属部門カラムに部門名が書かれていた場合 は、営業1課になった社員も全員、所属部門カラムを書き換える必要 が生じますが、部門コードが書かれている場合は002というコードに 変更はありませんから、何も書き換える必要がありません。代わり にDEPARTMENTテーブルの営業課の行を一つ書き換えるだけですむの です。 というわけで、EMPLOYEEテーブルを次のように変更します。 --------------------------------------------------- [EMPLOYEEテーブルのカラム] 社員番号、氏名、生年月日、所属部門コード --------------------------------------------------- たとえば、その具体的なデータは以下のような感じになります。 --------------------------------------------------- 00001、舟木和子、1970年11月12日、001 00002、安部泰三、1960年10月12日、001 00003、長内順平、1986年08月12日、002 --------------------------------------------------- この所属部門コードというカラムにはEMPLOYEEテーブルの外にある テーブルの主キーを使っている(DEPARTMENTテーブルの主キーを使っ ている)わけですが、外部の主キーを参照していることから外部キー あるいはフォーリン・キー(foreign key)と呼ぶことがあります。 外部キーは、いわば、そのテーブルと他のテーブルの関係付けを行う キーです。 今のEMPLOYEEテーブルの場合は、外部キーである所属部門コードのカ ラムを通してDEPARTMENTテーブルのデータを引き出すことができます。 たとえば、社員番号00001の舟木和子さんの場合は所属部門コードが001 であることから、DEPARTMENTテーブルの部門コード001から、総務課とい う部門名とXビル2階というオフィス所在地を引き出すことができます。 ところで、EMPLOYEEテーブルの中のある行に007という所属部門コード が指定されていたとしてみましょう。 もし、この007という部門コードがDEPARTMENTテーブルの中に存在しな かったら困りますね。 その社員はどこの部門に所属しているのかわからなくなります。 実際に、EMPLOYEEテーブルとの関係を無視してDEPARTMENTテーブルの ほうだけデータを削除してしまった場合などにこのような問題が発生 します。 そのために、外部キーはそれが参照している主キーとの整合性を維持 できるようにするためにさまざまな制御が行えるようになっています。 たとえば、営業課を廃止することになったとして、DEPARTMENTテーブル の中の部門コードが002の行を削除する場合、同時にその部門に所属する 社員の所属部門をEMPLOYEEテーブル上で空白にするのか、それとも所属 する社員のデータもすべて削除してしまうのか、あるいは所属する社員 が存在する限りはその部門をDEPARTMENTテーブルから削除できないよう にするのか、といった細かい制御も指定することができます。 このようにデータの整合性を管理することもRDBMSの大切な仕事の一つに なっています。 こういった複数の関係するテーブルを具体的にSQLでどのように作成し、 どのように維持管理するのかについては、次回説明していきます。 また、次回はもう少しテーブルを複雑にして、より実際のアプリケーショ ンで使う形に近づけて行きます。 (続く) ======================================================== ◆ 02.文法解説 [演算子] ======================================================== [算術用の二項演算子 %] %演算子は割り算(除算)を行ってその余りを返す演算子です。 たとえば、17を7で割ると余りが3になりますが、 int x = 17; int y = 7; int z = x % y; を実行すると、xの値がyの値で割られてその余り3がzに代入され ます。つまりzの値は3になります。 この演算子はC言語やC++では整数型オペランドに対してしか適用 されませんでしたが、Javaでは整数型のみならず浮動小数点数型の オペランドにも適用されるように拡張されています。 皆さんは割り算の余りの数については小学校で学び、そのときには 負の数の割り算は学んでいなかったと思いますが、Javaの%演算子は 負の数の割り算にも適用されます。 そして負の整数を割るときには余りは負の整数になります。 たとえば -17 % 7 を計算すると、余りは-3になります。 余りの符号はあくまで割られる数すなわち%演算子の第一オペランド の符号のほうに合わされ、割る数すなわち第二オペランドには関係 しません。 たとえば -17 % -7 の結果(余り)は-3になり、 17 % -7 の結果(余り)は3になります。 これらの余りの符号は、 (x / y) * y + (x % y) の計算結果がxにならなければならないことから来ています。 たとえばxが-17でyが7の場合、 (-17 / 7) * 7 + (-17 % 7) を計算すると (-2) * 7 + (-3) となり、最終的には -17 となり、xに一致します。 また、xが17でyが-7の場合は、 (17 / (-7)) * (-7) + (17 % (-7)) を計算すると (-2) * (-7) + (3) となり、最終的には 17 となり、xに一致します。 この%演算子においても、割り算をするにあたって、オペランドの 型に応じて以下の型変換が行われます。(あくまで割り算の計算の ための一時的な変換であってオペランドそのものが変わってしまう のではありません。) (1) どちらかのオペランドがdouble型であれば、他方もdoubleに変換 される。 (2) (1)に該当しない場合は、どちらかのオペランドがfloat型であれば、 他方もfloatに変換される。 (3) (1),(2)のどちらにも該当しない場合は、どちらかのオペランドが longであれば他方もlongに変換される。 (4) (1),(2),(3)のどれにも該当しない場合は、両方のオペランドが intに変換される。 (この型変換はこれまで説明してきた+, -, *, /の各演算子ともに同様です。) そして変換されたオペランドの値に対して割り算が行われ、その余り の数が同じ型のままで算出されます。 では浮動小数点数型(double型またはfloat型)のオペランドに対する 余りの算出とはどのようなものかというと、基本的には整数型に対する 余りの算出方法と同じです。 たとえば、割られる数(第一オペランド)と割る数(第二オペランド) がともに正の数の場合を考えると、第二オペランドを正の整数倍(何ら かの正の整数を掛ける)して、第一オペランドをこえないが第一オペラ ンドに一番近い値になるときの、第一オペランドとの差額が余りの数と いうことになります。このとき、余りの数は正の浮動小数点数になりま す。 割られる数(第一オペランド)が正の数で、割る数(第二オペランド) が負の数の場合は、第二オペランドに何らかの負の整数を掛けて、第一 オペランドをこえないが第一オペランドに一番近い値になるときの、 第一オペランドとの差額が余りの数ということになります。 このときも、余りの数は正の浮動小数点数になります。 割られる数(第一オペランド)が負の数で、割る数(第二オペランド) が正の数の場合は、第二オペランドに何らかの負の整数を掛けて、互い の絶対値で比較したとき第一オペランドをこえないが第一オペランドに 一番近い値になるときの、第一オペランドとの差額が余りの数というこ とになります。このとき、余りの数は負の浮動小数点数になります。 割られる数(第一オペランド)が負の数で、割る数(第二オペランド) も負の数の場合は、第二オペランドに何らかの正の整数を掛けて、互い の絶対値で比較したとき第一オペランドをこえないが第一オペランドに 一番近い値になるときの、第一オペランドとの差額が余りの数というこ とになります。このとき、余りの数は負の浮動小数点数になります。 このように、浮動小数点数の演算でもやはり、割られる数と余りの数の 符号は一致します。 なお、この浮動小数点数の余りの演算においては、この演算は一方また は両方のオペランドが正負の無限大やNaNの場合にも適用され、それぞれ 以下のような結果となります。 (1) 両方または一方のオペランドがNaNの場合は、結果はNaN。 (2) 第一オペランド(割られる数)が無限大の場合は、結果はNaN。 (3) 第二オペランド(割る数)が0の場合は、結果はNaN。(浮動小数点数 の0は厳密な0ではなく、ほぼ0というい0の近似値を意味しますので注意 してください。したがって、浮動小数点数の0で割ってもエラーにはなり ません。) (4) 第一オペランド(割られる数)が無限大で、かつ、第二オペランド (割る数)が0の場合も、結果はNaN。 (5) 第一オペランド(割られる数)が通常の数で第二オペランド(割る数) が無限大の場合は、結果は第一オペランド(割られる数)の値になる。 (6) 第一オペランド(割られる数)が0で第二オペランド(割る数)が 通常の数(0は除く)の場合は、結果は第一オペランド(割られる数=0) の値になる。 (続く) ================================================ ◆ 03.演習問題 ================================================ 下記のようなプログラムを作って、実行してみてください。 --------------------------------------------------------------------------------- public class ArithmeticOperationTest4 { public static void main(String[] args) { System.out.println("NaN % 5 = " + (Float.NaN % 5)); System.out.println("NaN % NaN = " + (Float.NaN % Double.NaN)); System.out.println("+∞ % 6 = " + (Float.POSITIVE_INFINITY % 6)); System.out.println("7.0 % 0.0 = " + (7.0 % 0.0)); System.out.println("0 % 0.0 = " + (0 % 0.0)); System.out.println("-∞ % 0 = " + (Float.NEGATIVE_INFINITY % 0)); System.out.println("6 % -∞ = " + (6 % Float.NEGATIVE_INFINITY)); System.out.println("-7 % -∞ = " + (-7 % Float.NEGATIVE_INFINITY)); System.out.println("-0.0 % 8 = " + (-0.0 % 8)); System.out.println("0 % 8.0 = " + (0 % 8.0)); } } --------------------------------------------------------------------------------- 結果はどうなりますか。 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ★ホームページ: 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. 不許無断複製 |