広告

■□■□■□■□■□■□■□■□■□■□■□■□■□■□■
                      2010年02月24日

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

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


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


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


========================================================
◆ 01.和暦を西暦に変換するクラス(続き)
========================================================


それでは、HumanInfoWindowが以前のHumanWindowからどのように
修正が加えられたのかを説明します。

まず、この修正の目的は、以前のHumanWindowが西暦の生年月日だ
けを対象に年齢計算を行っていたのに対して和暦で生年月日を入力
しても年齢計算をできるようにすることでした。

このために以下のような修正を加えています。

(1) 年号を「明治」「大正」「昭和」「平成」「西暦」から一つ
選択できるようにするために、ChoiceというGUI部品を組み込みま
した。
これについては、前回解説済みです。

(2) 和暦から西暦への変換をできるようにCalendarConverterを組み
込みました。

(3) 遅延生成のテクニックを使えるようにするために、Humanを
HumanInfoに置き換えて組み込みました。

(4) あと、LabelやButtonのラベル表示を少し変更したことにも
お気づきですね。でもこれは、重要な話ではありませんので説明
は省略します。


では、(2)のCalendarConverterと(3)のHumanInfoをどのように組み
込んだのか、見て行きましょう。


HumanInfoWindowのソース・コードを再度、下記に掲載します。

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

import java.awt.Button;
import java.awt.Choice;
import java.awt.Frame;
import java.awt.Label;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import jp.co.flsi.lecture.human.HumanInfo;
import jp.co.flsi.lecture.util.CalendarConverter;

public class HumanInfoWindow extends Frame {
   private HumanEventListener eventListener = new HumanEventListener();
   private HumanActionListener actionListener = new HumanActionListener();
   private Label labelDateOfBirth = new Label();
   private Choice nengoChoice = new Choice();
   private Label labelYear = new Label();
   private Label labelMonth = new Label();
   private Label labelDay = new Label();
   private Label labelName = new Label();
   private Label labelResponse = new Label();
   private Button instanceButton = new Button();
   private TextField textFieldYear = new TextField();
   private TextField textFieldMonth = new TextField();
   private TextField textFieldDay = new TextField();
   private TextField textFieldName = new TextField();
   private HumanInfo humanInfo = null;
   private CalendarConverter calendarConverter = null;
  
   class HumanEventListener implements WindowListener {
      public void windowActivated(WindowEvent e) {};
      public void windowClosed(WindowEvent e) {
         System.exit(0);
      };
      public void windowClosing(WindowEvent e) {
         Frame frame = (Frame)e.getSource();
         frame.setVisible(false);
         frame.dispose();
      };
      public void windowDeactivated(WindowEvent e) {};
      public void windowDeiconified(WindowEvent e) {};
      public void windowIconified(WindowEvent e) {};
      public void windowOpened(WindowEvent e) {};
   };
  
   class HumanActionListener implements ActionListener {
      public void actionPerformed(ActionEvent e) {
         Button button = (Button)e.getSource();
         HumanInfoWindow window = (HumanInfoWindow)button.getParent();
         int nengoIndex = nengoChoice.getSelectedIndex();
         int year = Integer.parseInt(window.getTextFieldYear().getText());
         int month = Integer.parseInt(window.getTextFieldMonth().getText());
         int day = Integer.parseInt(window.getTextFieldDay().getText());
         HumanInfo human = window.getHumanInfo();
         CalendarConverter calendarConverter = window.getCalendarConverter();
         if (nengoIndex < 4) {
            calendarConverter.setJaNameOfEra(nengoIndex);
            calendarConverter.setJaYear(year);
            calendarConverter.convertJaCal2GreCal();
            year = calendarConverter.getGreYear();
         }
         human.setDateOfBirth(year, month, day);
         human.setName(window.getTextFieldName().getText());
         window.getLabelResponse().setText("私は" + human.getName() + "です。" + human.getAge() + "歳です。");
      };
   };
  
   public HumanInfoWindow()  {
      super();
      setTitle("ヒュウマン劇場");
      setSize(400, 150);
      setLayout(null);
      labelDateOfBirth.setBounds(10, 30, 80, 20);
      nengoChoice.setBounds(120, 30, 80, 20);
      nengoChoice.add("明治");
      nengoChoice.add("大正");
      nengoChoice.add("昭和");
      nengoChoice.add("平成");
      nengoChoice.add("西暦");
      getTextFieldYear().setBounds(210, 30, 40, 20);
      labelYear.setBounds(255, 30, 20, 20);
      getTextFieldMonth().setBounds(290, 30, 20, 20);
      labelMonth.setBounds(315, 30, 20, 20);
      getTextFieldDay().setBounds(350, 30, 20, 20);
      labelDay.setBounds(375, 30, 20, 20);
      labelName.setBounds(10, 60, 60, 20);
      getTextFieldName().setBounds(70, 60, 320, 20);
      instanceButton.setBounds(120,90, 160, 20);
      getLabelResponse().setBounds(10, 120, 380, 20);
      add(labelDateOfBirth);
      add(nengoChoice);
      add(getTextFieldYear());
      add(labelYear);
      add(getTextFieldMonth());
      add(labelMonth);
      add(getTextFieldDay());
      add(labelDay);
      add(labelName);
      add(getTextFieldName());
      add(instanceButton);
      add(getLabelResponse());
      labelDateOfBirth.setText("生年月日:");
      labelYear.setText("年");
      labelMonth.setText("月");
      labelDay.setText("日");
      labelName.setText("氏名:");
      instanceButton.setLabel("年齢計算");
      instanceButton.addActionListener(actionListener);
      addWindowListener(eventListener);
      setVisible(true);
   }

   public TextField getTextFieldYear() {
      return textFieldYear;
   }

   public TextField getTextFieldMonth() {
      return textFieldMonth;
   }

   public TextField getTextFieldDay() {
      return textFieldDay;
   }

   public TextField getTextFieldName() {
      return textFieldName;
   }

   public Label getLabelResponse() {
      return labelResponse;
   }
  
   public HumanInfo getHumanInfo( ) {
      if (humanInfo == null) humanInfo = new HumanInfo();
      return humanInfo;
   }
  
   public CalendarConverter getCalendarConverter( ) {
      if (calendarConverter == null) calendarConverter = new CalendarConverter();
      return calendarConverter;
   }
  
   public static void main(String[] args) {
      HumanInfoWindow frame = new HumanInfoWindow();
   }

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


30〜31行目
-------------------------------------------------------
private HumanInfo humanInfo = null;
private CalendarConverter calendarConverter = null;
-------------------------------------------------------

および

136〜144行目
-------------------------------------------------------
public HumanInfo getHumanInfo( ) {
   if (humanInfo == null) humanInfo = new HumanInfo();
   return humanInfo;
}
  
public CalendarConverter getCalendarConverter( ) {
   if (calendarConverter == null) calendarConverter = new CalendarConverter();
   return calendarConverter;
}
-------------------------------------------------------

は、それぞれのフィールド(属性の変数)とgetメソッドを定義して
いますが、これらが遅延生成のテクニックを使ったものであることは、
もうおわかりですね。

そして、アクション・リスナーの定義の中で

57〜65行目
-------------------------------------------------------
HumanInfo human = window.getHumanInfo();
CalendarConverter calendarConverter = window.getCalendarConverter();
if (nengoIndex < 4) {
   calendarConverter.setJaNameOfEra(nengoIndex);
   calendarConverter.setJaYear(year);
   calendarConverter.convertJaCal2GreCal();
   year = calendarConverter.getGreYear();
}
human.setDateOfBirth(year, month, day);
-------------------------------------------------------

の記述によって、HumanInfoのインスタンスとCalendarConverterのインス
タンスを取り出したあと、nengoIndex(前回説明したChoiceで選択された行
の番号(インデックス))の値が3以下(4より小さい)の場合は(和暦なの
で)そのインデックス(これが年号を表現する番号になる)と年を
CalendarConverterのインスタンスにセットして和暦から西暦に変換させて
います。
そして変換後の年の値をyear変数に代入しています。
最後に変換後の西暦の生年月日をHumanInfoのインスタンスにセットしてい
ます。


その他のソース・コードは、もうすべて理解できますね。

わからないところがありましたら、下記Webページにて質問をお送りください。




========================================================
◆ 02.文法のコーナー [プリミティブ型]
========================================================

包括的な文法の説明をできるようにするために、今回から文法解説のコーナー
を設けることにしました。

まず第一回目は「プリミティブ型」の解説です。


以前、基本データ型(プリミティブ型)について少し触れましたが、ここでその
全貌をお話しておきます。

Javaには参照型と呼ばれるオブジェクトを表現する型の他に、プリミティブ型
と呼ばれるデータのみを持つ型があるのでしたね。
オブジェクトはメソッドを持ちますが、プリミティブ型はメソッドを持たず、
純粋にデータのみを持つ型です。

このプリミティブ型には、以下のようなものがあります。


(1) 文字
   型              サイズ(バイト数)        範囲
   char              2                    0 〜 65535
上記の範囲に書かれている数字は、文字を整数扱いして十進数表示したときの
値の範囲です(文字もコンピューターの内部では数値で表現され、処理されま
す)。
charは文字を入れるための型ですが、文字を整数扱いして処理することもでき
ます。
例えば、char型の変数に整数値を代入することもできるし、加減乗除などの計算
をすることもできます。

(例)
char  mojia = 65;
char  mojib;
mojib  =  mojia + 10;

なお、文字はコンピューターの内部では数値で符号(コード)化されますが
その数値表現の形式には、いくつかの種類があります。(日本の)パソコンでは
通常は「シフトJIS」と呼ばれる表現形式が使われていますが、Javaのプログラム
の内部では、「Unicode」(ユニコード)と呼ばれる表現形式が使われています。
したがって、Javaのchar型の変数に代入した文字は、Javaプログラムの内部では
Unicodeのコードとなって記憶されます。String型でも同じです。
このことは、本格的なプログラミングをするときに問題になることがあるので、
のちに詳しく説明いたします。

(2) 整数
  型               サイズ(バイト数)          範囲
  byte               1                      -128 〜 127       
  short              2                      -32768 〜 32767       
  int                 4                      -2147483648 〜 2147483647
  long               8                      -9223372036854775808〜9223372036854775807

(3) 浮動小数点数
  型                サイズ(バイト数)         範囲
  float              4                     ±3.4028235e+38〜±1.40e-45
  double             8                     ±1.7976931348623157e+308〜±4.9e-324
(注: e+38は10の38乗、e-45は10の-45乗を意味します。ちなみに、
e+2は10の2乗すなわち100を表し、e-2は10の-2乗つまり100分の1を表します。)

┌補足─────────────────────────┐
浮動小数点数は、科学技術計算など複雑な数値計算に用いられる
ことが多く、高速の処理が要求される場合が多いものです。
このため、通常のコンピューターには浮動小数点数専用の演算
機能が組み込まれているのが普通であり、その機能を使えば速く
処理することができます。
しかし、この浮動小数点数専用の演算処理はプラットフォーム
(どんな種類のコンピューターを使っているか)に依存し、コン
ピューターによって処理結果(精度)に違いが出てきます。
そこで、浮動小数点数の処理については、どのプラットフォーム
で実行しても同じ結果が出るように、Java独自の仕様(FP-strict
と呼ばれる)が導入されました。
このFP-strictを利用するには、strictfpという修飾子を指定し
ます。

strictfpはクラス、インターフェース、あるいはメソッドに指定
できます。
たとえば、クラスに指定する場合は、

strictfp public class NantokaKantoka {
    private float x;
    private double y;
        :
        :
}

のように指定します。

このようにstrictfpを指定した場合は、どのプラットフォームで
実行しても同じ処理結果が得られるので、Javaの「プラットフォ
ームに依存しない」というお題目を満たしていると言えますが、
コンピューターが本来持っている浮動小数点数の処理機能を生か
すことができないので、処理が遅くなってしまうという欠点があ
ります。
したがって、高速で処理したい(かつ複数のプラットフォームで
実行する必要はない)という場合にはstrictfpを指定しないこと
が望ましいです。

ただし、strictfpを指定しない場合でも

2.0 * Math.PI
(ここでMath.PIは円周率πを表す定数)

のような定数(コンパイル時に演算処理されて定数として扱わ
れる)は、strictfp扱いになります(コンパイルはどのプラッ
トフォームで実行しても同じ結果になる)。

なお、Javaでプログラミングしてもプラットフォーム依存にな
ってしまうものは、これ以外にもありますので、必要な時点で
また紹介します。
└───────────────────────────┘

(4) ブーリアン(論理値)
ブーリアンは、真(true)か偽(false)かの2つのうちのどちらかの値を持つこと
ができる型です。
  型                        範囲
  boolean                trueまたはfalse


なお、Javaのプリミティブ型は、もともとC言語の基本データ型(基本型ともいう)
をまねて作られたものですが、C言語とはサイズなどが異なるので注意してくださ
い。
もっとも、C言語(およびその拡張版であるC++)では、システム系(コンパイラー)
によってもサイズが異なるなど、曖昧さがあるのに対し、Javaではサイズが明確に
決まっています。



では、今回はここまでにします。



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

char型の変数に文字を代入するには、次のようにします。

char  a = 'a';    // 変数aに「a」という文字を代入
char  b = 'あ';  // 変数bに「あ」という文字を代入

では、String型の変数sに「a」という文字を代入するにはどうすればいいですか。
String  s  =
の後に何を書けばいいか考えなさい。
また、それでいいかどうか、実際に自分でプログラムを書いてテストしてみなさい。



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

今回の本文を参照してください。



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