広告

■□■□■□■□■□■□■□■□■□■□■□■□■□■□■
                      2011年12月11日

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

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


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


========================================================
◆ 01.データベースを使用するアプリケーションの開発(続き)
========================================================

前回getButton_1()メソッドの中にactionPerformed()メソッドの
編集をしたときに、最後のほうのコードを説明するのを忘れていた
ので、ちょっと説明を追加しておきます。

--------------------------------------------------------
table.setModel(getTableModelOfEmployee());
table.createDefaultColumnsFromModel();
--------------------------------------------------------

この1つ目のコードのsetModel()というメソッドはJTableに
TableModelのインスタンスをセットする(結び付ける)ため
のメソッドです。

JTableにモデル・オブジェクトを結び付けるには、JTableのイ
ンスタンス生成時にコンストラクターに引数としてモデル・オ
ブジェクトを渡す方法のほかに、このようにsetModel()メソッド
を使ってモデル・オブジェクトをセットする方法もあります。
いずれの方法を使ってもかまいません。

2つ目のコードのcreateDefaultColumnsFromModel()というメソッ
ドはJTableにTableModelのインスタンスから全列のデータを取り出
してJTable上にデータを新たに書き出します。
このときすでにJTableに表示されていたデータがあった場合は
それらを消去してからデータを書き直します。
要するにJTable上のデータをリフレッシュする働きを持っています。


それから、前回、「検索」のページの動作をテストしてみたら、
ウインドウが狭すぎてJTableの部分が見えづらいし、ウインドウ
を手で広げてみたら今度は「検索」ボタンとJTableの間の間隔が
開き過ぎて格好悪い、と感じた人もいるのではないでしょうか。

これらも少し調整しておきましょう。

まず、「検索」ボタンとJTableの間の間隔を固定するために以下の
操作を行ってみて下さい。(HumanResourceEntryPaneのDesignビュー
を開いておいて下さい。

(1) 「検索」タブをダブル・クリックすることにより、「検索」の
ページを開きます。

(2) 「検索」ボタンの土台になっているJPanelをクリックします。

(3) 左側の縦長の帯に行の番号が表示されるので、そのうちの3(こ
れは「検索」ボタンの土台になっているJPanelが貼りついている行の
番号)を右クリックし、「プロパティー」を選択します。

(4) 「Row Properties」ウインドウが開くので、その中の「Resize
behavior」という項目の「なし」を選択し、「OK」ボタンをクリック
します。

以上で、「検索」ボタンとJTableの間の間隔が固定され広がらなく
なりました。

次に、ウインドウ全体の大きさ(高さ)を少し広げるために以下の
操作を行ってください。

(1) HumanResourceJFrameをエディター(WindowBuilder Editor)で
開きます。

(2) 画像のタイトル・バー(JFrameという文字が書かれているあたり)
をクリックするか、あるいは、(Structure配下の)Components欄の
「(javax.swing.JFrame) - "JFrame"」という行をクリックします。

(3) 画像の周辺にハンドル(黒い小さな四角形)が表示されるので、
そのうち下辺の中央にあるハンドルをドラッグして下のほうに引っ張り、
[300 × 300]という表示になったら手を放しましょう

以上で、ウインドウ全体の大きさ(高さ)が広がりました。


いったん保管したあと、HumanResourceJFrameを実行してテストして
みましょう。
まだレイアウトに満足しない人は、さらに自分で微調整してみて
下さい。


ここまでで、「検索」機能のプログラミングの話は終わりにします。
エラー時の処理(たとえば年齢の欄に数値以外の文字を入力したとき
のエラー処理など)については「新規登録」のときと同様ですので
説明を省略します。



では次のステップとして、人事データを更新するためのプログラム作り
に進みましょう。

更新とは、データの一部を変更することであり、たとえば結婚して姓
が変わったので氏名を変更するとか、所属部署が変わったので変更す
るとか、新規登録のときに入力した生年月日が間違っていたので一部
修正するとかいった作業を意味します。

この場合、社員番号は同一人物であることを識別するための番号なの
で変更することはできません(社員番号は、データベース上では
プライマリー・キー(PRIMARY KEY)になっている)。

こういった更新の操作はJTable上で直接行うこともできます。
つまり、「検索」のページで検索して表示されたJTable上のデータに
対し、社員番号以外の列を変更(編集)できるようにするということ
が可能です。

しかし、今回はJTable上で直接編集する方法ではなく、「更新」の
専用のページを用意して、そこで編集する方法を用いることにします。

「更新」のページは「新規登録」のページとほとんど同じ画面イメー
ジにしますが、「登録」ボタンの代わりに「更新」というラベルが
書かれたボタンを使うなど若干違いがあります。

更新したいデータは、あらかじめ「検索」のページのJTableの中で選択
しておけば、「更新」のページの各欄に自動的にそれらのデータが
入力されるようにしますが、最初から「更新」のページですべての
データを手で入力してもよいものとします。


では、「更新」のページを作っていきましょう。
HumanResourceEntryPane.javaをエディター(WindowBuilder Editor)
で開いてください。 Designビューを開きます。

今回から説明は簡潔に済ませることにしますが、作り方は「新規登録」
のページと同じですから、わからなくなったら過去の記事を復習して
ください。

なお、今までは作業を簡単にするために、貼り付けるGUI部品の変数名
(あるいはBean Name)は自動的に与えられるものをそのまま使ってい
ましたが、今回から、わかりやすい変数名に変えるようにします。
(本来は、あとでソース・コードを見たときにどのGUI部品かすぐに
わかるような、わかりやすい名前をつけるべきなのです。)


(1) Palette(パレット)のContainers配下からJPanelを選択し、
「検索」タブの右側に貼り付けます。
変数名(Properties欄のVariable)はjPanelUpdateにします。

(2) title(Properties欄のTab配下のtitle)の値を「更新」にします。

(3) Layout(Properties欄のLayout)の値はGridBagLayoutを選択します。

(4) Palette(パレット)のComponents配下からJLabelを選択し、
「column 0, row 0」が表示される位置に貼り付け、変数名(Properties欄
のVariable)はjLabelUpdateにします。
textプロパティー(Properties欄のtext)の値を「以下を入力/変更してください。」
にします。

(5) 同様にJLabelを「column 0, row 1」が表示される位置に貼り付け、
変数名はjLabelEmpNumにします。
textプロパティーの値を「社員番号」にします。

(6) JTextFieldを「column 1, row 1」が表示される位置に貼り付け、
変数名はjTextFieldEmpNumにします。

(7) JLabelを「column 0, row 2」が表示される位置に貼り付け、
変数名はjLabelNameにします。
textプロパティーの値を「氏名」にします。

(8) JTextFieldを「column 1, row 2」が表示される位置に貼り付け、
変数名はjTextFieldNameにします。

(9) JLabelを「column 0, row 3」が表示される位置に貼り付け、
変数名はjLabelDayBirthにします。
textプロパティーの値を「生年月日」にします。

(10) JComboBoxを「column 1, row 3」が表示される位置に貼り付け、
変数名はjComboBoxEraにします。

(11) このjComboBoxEraの右側に列を増やすために、その上側の
横方向の帯に0, 1と列の番号が表示されているところを見て下さい。
その2の右側の何も番号が表示されていないところを右クリックし、
「Append Column」を選択して下さい。
そうすると、jComboBoxEraの右側に列が追加されます。

(12) そこで、JTextFieldを追加された列の「column 2, row 3」が
表示される位置に貼り付け、変数名はjTextFieldYearにします。

(13) 先ほどと同様な操作でjTextFieldYearの右側に列を追加します。

(14) JLabelを「column 3, row 3」が表示される位置に貼り付け、
変数名はjLabelYearにします。
textプロパティーの値を「年」にします。

(15) 先ほどと同様な操作でjLabelYearの右側に列を追加します。

(16) JTextFieldを「column 4, row 3」が表示される位置に貼り付け、
変数名はjTextFieldMonthにします。

(17) 先ほどと同様な操作でjTextFieldMonthの右側に列を追加します。

(18) JLabelを「column 5, row 3」が表示される位置に貼り付け、
変数名はjLabelMonthにします。
textプロパティーの値を「月」にします。

(19) 先ほどと同様な操作でjLabelMonthの右側に列を追加します。

(20) JTextFieldを「column 6, row 3」が表示される位置に貼り付け、
変数名はjTextFieldDayにします。

(21) 先ほどと同様な操作でjTextFieldDayの右側に列を追加します。

(22) JLabelを「column 7, row 3」が表示される位置に貼り付け、
変数名はjLabelDayにします。
textプロパティーの値を「日」にします。

(23) JLabelを「column 0, row 4」が表示される位置に貼り付け、
変数名はjLabelDepartにします。
textプロパティーの値を「所属部署」にします。

(24) JComboBoxを「column 1, row 4」が表示される位置に貼り付け、
変数名はjComboBoxDepartにします。

(25) JPanelを「column 0, row 5」が表示される位置に貼り付け、
変数名はjPanelUpdateButtonにします。

(26) JButtonを先ほど貼り付けたjPanelUpdateButtonの中に貼り付け、
変数名はjButtonUpdateにします。
textプロパティーの値を「更新」にします。


では、次にレイアウトの調整をしましょう。

(27) jLabelUpdateをクリックすることによってハンドルを表示させ、
右端のハンドルを右方向にドラッグして、目いっぱい(8セル分)
幅を広げておきましょう。
そして、その上にある矢印のアイコンが並んでいる帯(列の番号が
並んでいる帯の上にある帯)の中の左向きの矢印のボタンをクリック
することによって、文字列を左揃えにします。(代わりにProperties欄
のConstraints配下のanchorの値をWESTに選択することによっても左揃え
にできます。)

(28) jTextFieldEmpNumをクリックすることによってハンドルを表示させ、
右端のハンドルを右方向にドラッグして、目いっぱい(7セル分)
幅を広げておきましょう。

(29) jTextFieldNameをクリックすることによってハンドルを表示させ、
右端のハンドルを右方向にドラッグして、目いっぱい(7セル分)
幅を広げておきましょう。

(30) jTextFieldYearをクリックし、にProperties欄のConstraints配下
のweightxの値を2.0にします。すると、このテキスト・フィールドの幅
が広がりますね。

(31) jComboBoxDepartをクリックすることによってハンドルを表示させ、
右端のハンドルを右方向にドラッグして、目いっぱい(7セル分)
幅を広げておきましょう。

(32) jPanelUpdateButtonをクリックすることによってハンドルを表示させ、
右端のハンドルを右方向にドラッグして、目いっぱい(8セル分)
幅を広げておきましょう。



ところで、この「更新」のページと「新規登録」のページはほとんど同じ
なので、共通部品化しておけば、二重作業の手間を省くことができます。
たとえば、これらのページに貼り付ける複数のGUI部品をその土台になって
いるJPanelごと一つの複合オブジェクトにして共通の部品としておけば、
「新規登録」のページと「更新」のページのどちらにも同じ複合オブジェ
クトを貼り付けて使用することができます。(ただし、同じオブジェクト
といっても「新規登録」のページと「更新」のページとではそれぞれ別の
インスタンスになります。ボタンの文字列などはそれぞれインスタンス変数
として別々に値を設定できるようにします。)

でも、今更作業をやり直すのは面倒ですから、今回はそのままにしておき
ます。

このような共通部品化は本来、プログラミングの前の設計という工程で行い、
プログラミング(実装の工程)では設計された通りにコーディングすること
になります(ただし、各工程間の多少の行き戻りはあります)。
この話は、また、のちに開発の全工程(特に設計の工程)の説明をするときに
詳しく解説いたします。



では、続いてソース・コードの編集に進んで行きましょう。

まず、jComboBoxEra(「生年月日」欄の年号のJComboBox)とjComboBoxDepart
(「所属部署」欄のJComboBox)ですが、これらにリストするデータは基本的
に「新規登録」のページと同じものです。

まず、「生年月日」欄の年号のJComboBox(jComboBoxEra)のほうですが、

----------------------------------------------
private JComboBox getJComboBoxEra() {
   if (jComboBoxEra == null) {
      jComboBoxEra = new JComboBox();
   }
   return jComboBoxEra;
}
----------------------------------------------

を次のように編集すれば「新規登録」のページと同じ内容のリストになり
ます。(035号のgetJComboBox()メソッド参照)

----------------------------------------------
private JComboBox getJComboBoxEra() {
   if (jComboBoxEra == null) {
      jComboBoxEra = new JComboBox();
      jComboBoxEra.addItem("明治");
      jComboBoxEra.addItem("大正");
      jComboBoxEra.addItem("昭和");
      jComboBoxEra.addItem("平成");
      jComboBoxEra.addItem("西暦");
   }
   return jComboBoxEra;
}
----------------------------------------------

しかし、ちょっと待ってください。

getJComboBox()メソッドとgetJComboBoxEra()メソッドで同様の内容に
なっているのであれば、共通部分を取り出して共通部品化できるはず
です。
というか、「明治」「大正」「昭和」・・・という年号のデータは将来
変わる(平成の次の年号が将来作られる)ものであり、2つのメソッド
で重複して持っていると将来の変更時にも2箇所変更しなければならない
ことになり、(2箇所だけならまだいいですが、もっと多いと)この種の
重複は作業を面倒にするだけでなく、修正し忘れを起すなど不具合を招く
原因にもなります。
そういう意味でも共通部品化を行っておくことが鉄則になります。

実は、ここの共通部品化は現段階でも簡単にできますので、やってみま
しょう。
なお、本来ならばComboBoxModelオブジェクトに「明治」「大正」「昭和」
・・・というデータを持たせて分離するのがオーソドックスなやり方です
が、ここではもっと安直な方法をお教えします。

なお、これから行う「プログラムの機能は変わらないけれど、後の生産性
を向上させたり、後に不具合を招く原因になりがちな要素を取り除くため
にソース・コードを変更するような作業」を「リファクタリング(refactoring)」
といいます。


はい、では、getComboBox()メソッドのソース・コード

----------------------------------------------
private JComboBox getComboBox() {
   if (comboBox == null) {
      comboBox = new JComboBox();
      comboBox.addItem("明治");
      comboBox.addItem("大正");
      comboBox.addItem("昭和");
      comboBox.addItem("平成");
      comboBox.addItem("西暦");
   }
   return comboBox;
}
----------------------------------------------

の中の

----------------------------------------------
      comboBox.addItem("明治");
      comboBox.addItem("大正");
      comboBox.addItem("昭和");
      comboBox.addItem("平成");
      comboBox.addItem("西暦");
----------------------------------------------

の部分を選択(ドラッグすることにより色を反転させる)し、メニュー・バー
の「リファクタリング」→「メソッドの抽出」を選択します。

「メソッドの抽出」ウインドウの「メソッド名」欄には
nameOfEraComboBoxSetup
と入力することにしましょう。「アクセス修飾子」は「private」のままでいい
です(このメソッドは外部から呼び出されることはありませんので)。

「プレビュー」ボタンをクリックし、次の画面で変更内容を確認した後、「OK」
ボタンをクリックします。

そうするとgetComboBox()メソッドが変更されると同時にnameOfEraComboBoxSetup()
メソッドが生成されて、以下のようなソース・コードになりますね。

----------------------------------------------
private JComboBox getComboBox() {
   if (comboBox == null) {
      comboBox = new JComboBox();
      nameOfEraComboBoxSetup();
   }
   return comboBox;
}

private void nameOfEraComboBoxSetup() {
   comboBox.addItem("明治");
   comboBox.addItem("大正");
   comboBox.addItem("昭和");
   comboBox.addItem("平成");
   comboBox.addItem("西暦");
}
----------------------------------------------

でも、nameOfEraComboBoxSetup()メソッドはまだこのままでは共通部品とは
言えません。

共通部品にするためには、さらに次の作業を行います。

まず、ソース・コードの中のnameOfEraComboBoxSetup()のところをクリック
してカーソルを入れておいてから、メニュー・バーの「リファクタリング」→
「メソッド・シグニチャーの変更」を選択します。

「メソッド・シグニチャーの変更」ウインドウにおいて「パラメーター」タブ
の右側の「追加」ボタンをクリックし、「型」欄に「JComboBox」、「名前」欄
に「aComboBox」、「デフォルト値」に「comboBox」と入力し、「プレビュー」
ボタンをクリックし、次の画面で変更内容を確認した後、「OK」ボタンをクリッ
クします。

すると、nameOfEraComboBoxSetup()が新しくパラメーター(引数)つきのメソッ
ドに作り変えられ、下記のようになります。

----------------------------------------------
private JComboBox getComboBox() {
   if (comboBox == null) {
      comboBox = new JComboBox();
      nameOfEraComboBoxSetup(comboBox);
   }
   return comboBox;
}

private void nameOfEraComboBoxSetup(JComboBox aComboBox) {
   comboBox.addItem("明治");
   comboBox.addItem("大正");
   comboBox.addItem("昭和");
   comboBox.addItem("平成");
   comboBox.addItem("西暦");
}
----------------------------------------------

まだ共通部品化は完成していません。nameOfEraComboBoxSetup()メソッド
の中の

----------------------------------------------
   comboBox.addItem("明治");
   comboBox.addItem("大正");
   comboBox.addItem("昭和");
   comboBox.addItem("平成");
   comboBox.addItem("西暦");
----------------------------------------------

の部分のcomboBoxをaComboBoxに書き換える必要があります。手で書き換え
てもいいですが、メニュー・バーの「編集」→「検索/置換」を使うと便利
です。ただし、置換する場所を間違えないように気を付けてください。

以上で、先ほどのソース・コードが

----------------------------------------------
private JComboBox getComboBox() {
   if (comboBox == null) {
      comboBox = new JComboBox();
      nameOfEraComboBoxSetup(comboBox);
   }
   return comboBox;
}

private void nameOfEraComboBoxSetup(JComboBox aComboBox) {
   aComboBox.addItem("明治");
   aComboBox.addItem("大正");
   aComboBox.addItem("昭和");
   aComboBox.addItem("平成");
   aComboBox.addItem("西暦");
}
----------------------------------------------

に変わりましたね。このソース・コードがやることは元々のgetJComboBox()
がやっていたことと同じだけど、nameOfEraComboBoxSetup()メソッドという
共通部品が抽出されたという意味があります。

文章で書くと説明が長くなってしまったけれど、慣れると簡単な作業です。


では、このnameOfEraComboBoxSetup()メソッドを利用してgetJComboBoxEra()
メソッドを変更してみましょう。

getJComboBoxEra()メソッドを下記のように編集してください。

----------------------------------------------
private JComboBox getJComboBoxEra() {
   if (jComboBoxEra == null) {
      jComboBoxEra = new JComboBox();
      nameOfEraComboBoxSetup(jComboBoxEra);
   }
   return jComboBoxEra;
}
----------------------------------------------

以上で、今後新しい年号ができたときには、共通部品のnameOfEraComboBoxSetup()
メソッドだけを変更すればよいことになり、重複した修正は不要になります。


ところで、本来は「明治」「大正」「昭和」・・・といった、将来追加/変更さ
れる可能性のあるデータは、上記のようにプログラムの中に固定するのではなく、
外部のデータにして外部から読み込むようにすることが望ましいです。
が、ここでは話が長くなるので省略します。


では、編集が終わったら、ここでまたテスト(HumanResourceJFrameの実行)を
して、生年月日のJComboBoxの動きを確認してみてください。



では次に進みましょう。
「所属部署」欄のJComboBox(jComboBoxDepart)のほうは、

--------------------------------------------------------
private JComboBox getJComboBoxDepart() {
   if (jComboBoxDepart == null) {
      jComboBoxDepart = new JComboBox();
   }
   return jComboBoxDepart;
}
--------------------------------------------------------

を(「新規登録」のページで編集した)getComboBox_1()メソッド(037号以降
参照)と同様にするには、次のように編集することになりますが、

--------------------------------------------------------
private JComboBox getJComboBoxDepart() {
   if (jComboBoxDepart == null) {
      DepartmentDbManager aDbm = new DepartmentDbManager();
      aDbm.getAllData();
      ComboBoxModelOfDepartment model = new ComboBoxModelOfDepartment();
      model.setDepartmentList(aDbm.getDepartmentList());
      jComboBoxDepart = new JComboBox(model);
      jComboBoxDepart.setSelectedIndex(0);
   }
   return jComboBoxDepart;
}
--------------------------------------------------------

これまたgetComboBox_1()メソッドとの共通部分を取り出して共通部品化でき
そうですね。


はい。では、やってみましょう。

まず、getComboBox_1()メソッドのソース・コード

--------------------------------------------------------
private JComboBox getComboBox_1() {
   if (comboBox_1 == null) {
         DepartmentDbManager aDbm = new DepartmentDbManager();
         aDbm.getAllData();
         ComboBoxModelOfDepartment model = new ComboBoxModelOfDepartment();
         model.setDepartmentList(aDbm.getDepartmentList());
         comboBox_1 = new JComboBox(model);
         comboBox_1.setSelectedIndex(0);
   }
   return comboBox_1;
}
--------------------------------------------------------

の中の

--------------------------------------------------------
         DepartmentDbManager aDbm = new DepartmentDbManager();
         aDbm.getAllData();
         ComboBoxModelOfDepartment model = new ComboBoxModelOfDepartment();
         model.setDepartmentList(aDbm.getDepartmentList());
--------------------------------------------------------

の部分を選択(ドラッグすることにより色を反転させる)し、メニュー・バー
の「リファクタリング」→「メソッドの抽出」を選択します。

「メソッドの抽出」ウインドウの「メソッド名」欄には「createComboBoxModelOfDepart」
と入力することにしましょう。
「アクセス修飾子」は「private」のままでいいです(このメソッドは
外部から呼び出されることはありませんので)。

「プレビュー」ボタンをクリックし、次の画面で変更内容を確認した後、
「OK」ボタンをクリックします。

そうするとgetComboBox_1()メソッドが変更されると同時に
createComboBoxModelOfDepart()メソッドが生成されて、以下のような
ソース・コードになりますね。

--------------------------------------------------------
private JComboBox getComboBox_1() {
   if (comboBox_1 == null) {
      ComboBoxModelOfDepartment model = createComboBoxModelOfDepart();
      comboBox_1 = new JComboBox(model);
      comboBox_1.setSelectedIndex(0);
   }
   return comboBox_1;
}

private ComboBoxModelOfDepartment createComboBoxModelOfDepart() {
   DepartmentDbManager aDbm = new DepartmentDbManager();
   aDbm.getAllData();
   ComboBoxModelOfDepartment model = new ComboBoxModelOfDepartment();
   model.setDepartmentList(aDbm.getDepartmentList());
   return model;
}
--------------------------------------------------------


ついでにgetComboBox_1()のほうは、もう少し簡単になりますね。

--------------------------------------------------------
private JComboBox getComboBox_1() {
   if (comboBox_1 == null) {
      comboBox_1 = new JComboBox(createComboBoxModelOfDepart());
      comboBox_1.setSelectedIndex(0);
   }
   return comboBox_1;
}
--------------------------------------------------------

というふうに変更しましょう。このほうが余計な変数の宣言文が無くなり、
すっきりします。
何を変更したかわかりますね。


はい。では、getJComboBoxDepart()のほうも同様に変更しましょう。

--------------------------------------------------------
private JComboBox getJComboBoxDepart() {
   if (jComboBoxDepart == null) {
      jComboBoxDepart = new JComboBox(createComboBoxModelOfDepart());
      jComboBoxDepart.setSelectedIndex(0);
   }
   return jComboBoxDepart;
}
--------------------------------------------------------

というふうに編集します。

ここで、テスト(HumanResourceJFrameの実行)して動きを確認してみま
しょう。(所属部署のJComboBoxの動きを確認しましょう。)



ところで、このアプリケーションでは、データベースのDEPARTMENTテーブル
は1回データを取り出したら、再度取り出し直す必要はありません。
DEPARTMENTテーブルのデータの更新や削除は行わないからです。

したがって、createComboBoxModelOfDepart()メソッドの中の

--------------------------------------------------------
   aDbm.getAllData();
--------------------------------------------------------

のコードは1回だけ実行すればいいのです。

ところが、createComboBoxModelOfDepart()メソッドはgetComboBox_1()メ
ソッドでもgetJComboBoxDepart()メソッドでも呼び出されますから、
aDbm.getAllData()のコードが重複して2回呼び出されることになります。
(今のアプリケーションではデータ量が少ないから問題にはなりませんが、
データ量が多いときには問題になります。)

したがって、無駄をなくすために1回の呼び出しだけですむように変更し
ましょう。

まず、createComboBoxModelOfDepart()メソッドの中の

--------------------------------------------------------
DepartmentDbManager aDbm = new DepartmentDbManager();
--------------------------------------------------------

の行のaDbmをクリックしてカーソルを入れておき、メニュー・バーの
「リファクタリング」→「ローカル変数をフィールドに変換」を選択
します。
「ローカル変数をフィールドに変換」ウインドウにおいて「フィールド名」
をわかりやすく「departDbm」に書き換えておきましょう。「アクセス修飾子」
は「private」のままにします。
「初期化」の欄は「現在のメソッド」を選択しておきます。

そして「プレビュー」ボタンをクリックします。

次にプレビューのウインドウになりますので、リファクタリングによってどの
ような変更がなされるのか内容を確認した後、「OK」ボタンをクリックします。

createComboBoxModelOfDepart()メソッドのソース・コードが

--------------------------------------------------------
private ComboBoxModelOfDepartment createComboBoxModelOfDepart() {
   departDbm = new DepartmentDbManager();
   departDbm.getAllData();
   ComboBoxModelOfDepartment model = new ComboBoxModelOfDepartment();
   model.setDepartmentList(departDbm.getDepartmentList());
   return model;
}
--------------------------------------------------------

に変更され、別の場所にdepartDbmのフィールド定義が生成されますね。

以上の作業で、メソッド内でしか生きていなかった変数(aDbm)がクラス
のフィールド(departDbm)に昇格(変換)されることにより、クラス
(HumanResourceEntryPane)のインスタンスが存在している限り生き続ける
ことになります。
そして、この変数(フィールド)に代入されたDepartmentDbManagerのイン
スタンスも、HumanResourceEntryPaneのインスタンスが存在している限り
生き続けることになります。

ただし、上のcreateComboBoxModelOfDepart()のままでは、メソッドを実行
するたびに新たにDepartmentDbManagerのインスタンスが生成され、フィールド
departDbmに代入されることになります。これでは、まだ無駄の解決には
なっていません。

そこで、このcreateComboBoxModelOfDepart()メソッドのソース・コードを
さらに

--------------------------------------------------------
private ComboBoxModelOfDepartment createComboBoxModelOfDepart() {
   if (departDbm == null) {
      departDbm = new DepartmentDbManager();
      departDbm.getAllData();
   }
   ComboBoxModelOfDepartment model = new ComboBoxModelOfDepartment();
   model.setDepartmentList(departDbm.getDepartmentList());
   return model;
}
--------------------------------------------------------

に修正しましょう。これはたんにif文を追加しただけですね。

これで、DepartmentDbManagerのインスタンス生成やgetAllData()メソッド
の実行が1回だけになります。


では、編集が終わったら、またテスト(HumanResourceJFrameの実行)をして
おきましょう。「更新」のページの生年月日や所属部署のリストがちゃんと
表示されることを確認してください。


では、今回はここまで。


(続く)


では、また来週。




========================================================
◆ 02.文法解説 [演算子]
========================================================

[ビットのシフト演算子<< >> >>>]

まずお膳立てのために「2の補数表現」について説明しておきましょう。

コンピューターの内部では数は2進数、すなわち0と1だけで表現されている
ことはすでに説明しましたね。
そして、十進数では10で位が上がるのに対して2進数では2で位があがるの
でした。

つまり、2進数表現では、1を段々と加えていくと

000 + 001 = 001 (十進数では1)
001 + 001 = 010 (十進数では2)
010 + 001 = 011 (十進数では3)
011 + 001 = 100 (十進数では4)
100 + 001 = 101 (十進数では5)
101 + 001 = 110 (十進数では6)

というふうに位があがっていきます。

ところで、コンピューターの内部は0と1だけで表現されていて、-(マイナス)
の記号など存在しませんが、負の数はどうやって表現しているのでしょうか。


実は、コンピューターの内部では「2の補数」と呼ばれる表現形式で負の数を
表現しています。

「2の補数」とは何かについて、例をあげながら説明しましょう。

まず、

-1 + 1 = 0

という計算式を思い出してください。-1に1を加えると0になります。
言い換えると、1を加えると0になるような数が-1です。

同様に

-2 + 2 = 0

つまり、2を加えると0になるような数が-2です。

以下同様に、

3を加えると0になるような数が-3。
4を加えると0になるような数が-4。
5を加えると0になるような数が-5。・・・・

これをint型の内部表現で示すと

11111111111111111111111111111111



1

を加えると頭の中の計算では

100000000000000000000000000000000

になりますが、int型は32ビット(4バイト)なので、コンピューター
内部では一番左側の1は記憶域からはみ出して消えてしまいます。
つまり、

00000000000000000000000000000000

になってしまいます。そうすると、これはただの0ですから、


11111111111111111111111111111111

は1を加えると0になる数、すなわち-1を表現していると考えることが
できます。

同様に


11111111111111111111111111111110


2
つまり二進数表現では

00000000000000000000000000000010

を加えると

100000000000000000000000000000000

すなわち、コンピューター内部の記憶域では

00000000000000000000000000000000

になります。

つまり、

11111111111111111111111111111110

は-2を表現していると考えることができます。

同様にして

11111111111111111111111111111101は-3を
11111111111111111111111111111100は-4を
11111111111111111111111111111011は-5を・・・・

表現していると考えることができます。
こういった負の数の表現方法を「2の補数」表現といいます。

コンピューターの内部では、この2の補数表現で負の数を表現して
いるのです。

そして、コンピューターの内部では、一番左端のビットが1のときは
負の数で、0のときは正の数(ただしすべてのビットが0のときは0)
と判断することになっています。

そうするとint型の正の最大数は

01111111111111111111111111111111 (十進数表現では2147483647)

負の最小数は

10000000000000000000000000000000 (十進数表現では-2147483648)

になります。




さて、ここからビットのシフト演算子(shift operator)<< >> >>>の
お話に入ります。

ビットのシフト(shift)とは、ビット・パターンを左方向または右方向
にずらすことを意味します。

たとえば、

00000000000000000000000000000011

を左方向に2ビットだけシフトすると

00000000000000000000000000001100になり、

同様に

00000000000000000000000000000100

を右方向に1ビットだけシフトすると

00000000000000000000000000000010

になります。

これらのうち左方向のシフトを行うための演算子が<<で、
たとえば、

int a = 3;
int b = a << 2;

のように使用します。<<の左側のオペランドにはシフトの対象になる
データ(を持つ変数)を指定し、右側のオペランドにはシフトする
ビット数を指定します。

同様に右方向のシフトを行うための演算子が>>で、
たとえば、

int c = 4;
int d = c >> 1;

のように使用します。オペランドの指定は<<の場合と同じです。

なお、シフトすることによって新しくできるビットは、上記のように
<<の場合は0が埋められますが、>>については元の一番左端のビットと
同じもの(一番左端のビットは「符号ビット」と呼ばれることがあり、
正の数なら0負の数なら1になっている)で埋められます。
なお、右方向のシフトには>>のほかに>>>というのもあり、>>>の場合は
左側に新しくできるビットは0で埋められます。それ以外の働きは>>と
同じです。

たとえば、

int c = 4;
int d = c >>> 1;

のように使用します。

シフト演算子もやはり、演算の対象になるのはintやlongの整数型です。
なお、ずらすビット数(右側のオペランド)はint型に対しては0〜31、
long型に対しては0〜63の範囲内で指定する必要があります。


(続く)



================================================
◆ 03.演習問題
================================================


1.

上記の演算子の振る舞いを確認するために、下記のようなプログラムを作っ
て実行してみてください。
また、実行結果がどうしてそのようになるのか考えてください。

--------------------------------------------------------
public class BitOperationTest2 {

   public static void main(String[] args) {
      int x = 1;
      int y = -1;
      int z = x >> 1;
      System.out.println("\n[Example 1]");
      System.out.println("int x = 1;");
      System.out.println("xのビット・パターン = 00000000000000000000000000000001");
      System.out.println("int y = -1;");
      System.out.println("yのビット・パターン = 11111111111111111111111111111111");
      System.out.println("z = x >> 1;");
      System.out.println("Result:  z = " + z);
      z = y >> 1;
      System.out.println("z = y >> 1;");
      System.out.println("Result:  z = " + z);
      z = y >>> 1;
      System.out.println("z = y >>> 1;");
      System.out.println("Result:  z = " + z);
      z = x << 2;
      System.out.println("z = x << 2;");
      System.out.println("Result:  z = " + z);
      z = y << 2;
      System.out.println("z = y << 2;");
      System.out.println("Result:  z = " + z);
      z = x << 31;
      System.out.println("z = x << 31;");
      System.out.println("Result:  z = " + z);
     
      int x1 = 4;
      System.out.println("\n[Example 2]");
      System.out.println("int x = 4;");
      System.out.println("xのビット・パターン = 00000000000000000000000000000100");
      int z1 = x1 >> 2;
      System.out.println("z = x >> 2;");
      System.out.println("Result:  z = " + z1);
      int y1 = -4;
      System.out.println("int y = -4;");
      System.out.println("yのビット・パターン = 11111111111111111111111111111100");
      z1 = y1 >> 2;
      System.out.println("z = y >> 2;");
      System.out.println("Result:  z = " + z1);
      z1 = y1 >> 1;
      System.out.println("z = y >> 1;");
      System.out.println("Result:  z = " + z1);
      z1 = x1 >>> 2;
      System.out.println("z = x >>> 2;");
      System.out.println("Result:  z = " + z1);
      z1 = y1 >>> 2;
      System.out.println("z = y >>> 2;");
      System.out.println("Result:  z = " + z1);
      z1 = y1 >>> 1;
      System.out.println("z = y >>> 1;");
      System.out.println("Result:  z = " + z1);
     
      long x2 = 1;
      long y2 = -1;
      long z2 = x2 >> 1;
      System.out.println("\n[Example 3]");
      System.out.println("long x2 = 1;");
      System.out.println("x2のビット・パターン = 0000000000000000000000000000000000000000000000000000000000000001");
      System.out.println("long y2 = -1;");
      System.out.println("y2のビット・パターン = 1111111111111111111111111111111111111111111111111111111111111111");
      System.out.println("z2 = x2 >> 1;");
      System.out.println("Result:  z2 = " + z2);
      z2 = y2 >> 1;
      System.out.println("z2 = y2 >> 1;");
      System.out.println("Result:  z2 = " + z2);
      z2 = y2 >>> 1;
      System.out.println("z2 = y2 >>> 1;");
      System.out.println("Result:  z2 = " + z2);
      z2 = x2 << 2;
      System.out.println("z2 = x2 << 2;");
      System.out.println("Result:  z2 = " + z2);
      z2 = y2 << 2;
      System.out.println("z2 = y2 << 2;");
      System.out.println("Result:  z2 = " + z2);
      z2 = x2 << 63;
      System.out.println("z2 = x2 << 63;");
      System.out.println("Result:  z2 = " + z2);
   }
}
--------------------------------------------------------


2.

前回のビット演算の復習として、int型の変数の右から0ビット目が1であれば
「ド」を、1ビット目が1であれば「レ」を、2ビット目が1であれば「ミ」を、
3ビット目が4であれば「ファ」を、4ビット目が1であれば「ソ」を、5ビット
目が1であれば「ラ」を、6ビット目が1であれば「シ」を、7ビット目が1であ
れば「ド」を返すメソッドを作ってみてください。

なお、同時に複数のビットが1になっていれば、複数の文字(文字列)を返す
ものとします。

戻り値はString型とします。


ヒント:
十進数で表現すれば「ド」は1、「レ」は2、「ミ」は4、「ファ」は8、・・・。
「ドレミ」は1+2+4=7になります。



(次回に続く。)


では、また来週。



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      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) 2011 Future Lifestyle Inc. 不許無断複製