Java入門:文法編









Java入門
文法編

















この教科書はBookletを利用して作成している。

目 次

第1部 Javaの文法
 0章 はじめに
 1章 最初のJavaプログラム
 2章 値の種類と式
 3章 入力と例外処理
 4章 条件分岐
 5章 繰り返し
 6章 配列
 7章 クラス・オブジェクト

第2部 ウィンドウアプリの開発
 8章 最初のウィンドウアプリ
 9章 部品1
10章 部品2
11章 コマンドによる部品追加
12章 簡易エディタ
13章 ファイル入出力
14章 簡易エディタの拡張

Ⓐ を付けた項目は、時間の関係で面接授業では扱わない発展的内容なので、自学自習する際の参考にして欲しい。

参考:超入門
    1.準備
    2.外観の設計
    3.動作の記述

本書の見方
ページをめくる
左(右)矢印キーを押す
1ページ分の移動
左右上端にある[Next]、[Previous]タブをクリックする
章の頭に移動
右上の【章の移動】タブをクリックし、現れた章を選ぶ
ページのジャンプ
右上のページ番号表示タブをクリックし、現れたページを選ぶ
画像の拡大およびリンク先への移動
画像やリンク先をクリックすれば、別ウィンドウ(タブ)で表示される

第0章 はじめに

0.1 講義の目標・方法

1.講義の目標

Javaによるプログラミング実習を通して、Javaの基本とWindowsアプリケーション開発に関わる諸概念とり わけオブジェクト指向プログラミングおよびイベント駆動型プログラミングについて学習する。 開発環境としては、ビジュアルな統合開発環境であるNetBeansを利用する。

2.学習の方法

Javaによるプログラミングから順を追って学習し、最終的には簡単なテキストエディタを開発する。毎回の授業は、コンピュータ上に用意された資料を用いて行い、その回の課題プログラムを 時間内に完成させることを目標とする。

0.2 Javaの基礎知識

1.Javaはどのコンピュータ(環境)でも動く

理由:Java仮想機械が多くのOSやブラウザに組み込まれているから。
Java仮想機械はJavaのクラスファイル(___.class)を実行する環境のことで、具体的にはjava.exeとそれに関連するプログラムから構成される。
確認:コマンドプロンプト(スタート→すべてのプログラム→Windowsシステムツール→コマンドプロンプト)で
  >java
と入力する。使い方を示すメッセージが表示される(筈)。表示されない場合は、Java実行環境をインストールする。

2.Javaプログラムの翻訳

Java言語で書かれたプログラムがJava仮想機械上で直接動くわけではない。 Javaのプログラムファイル(___.java)をJava仮想機械の実行形式であるクラスファイル(___.class)に翻訳するには、Java開発環境が必要である。

確認:コマンドプロンプトで
   >javac
と入力する。「内部コマンド…として認識されていません」というメッセージが出たら、Java開発環境が 1.ないか、2.見つからないか、のどちらかである。
  1. Javaの開発環境がない場合はJ2SEをインストールする。
  2. Javaの開発環境あるが見つからない場合には、例えば以下のようにjavac、javaコマンドのあるディレクトリへのPathをシステムに教える。
     >path=C:\Program Files\Java\jdk1.8.0_151\bin;%path%
詳しく知りたい人は、Javaの入門書を見るか、山崎(yamasaki.hideki@ouj.ac.jp)に相談して欲しい。(注.Javaの実行環境や開発環境のインストールは後に述べる統合開発環境NetBeansのインストールと一緒に行うことを勧める。)

実習1.Ⓐコンソールアプリケーションの作成・実行
  1. 次の内容のファイルを作成し、ファイル名 ___.javaで適当な場所(例えばコマンドプロンプトが開くフォルダ)に保存する。ファイル名とクラス名は同じでなければならない。また、Javaでは大文字と小文字は区別されるので、StringやSystemの頭文字は大文字にする。
        public class ___ {
            public static void main(String[] args) {
                System.out.println("Hello!");
            }
        }
  2. コマンドプロンプトを起動し、必要なら cd 命令を使って、1.で作成したファイルを保存したフォルダに移動する。
  3. ___.java をコンパイルする
    >javac ___.java
  4. 4.でできた ___.class を(Java仮想機械で)実行する
    >java ___

Javaのプログラムを実行すると、メインメソッド
    main(String[] args) { ・・・ }
が実行されるので、このプログラムでは、その内部に書かれた命令
    System.out.println("Hello!");
にしたがって、(標準出力に) Hello! と表示される。

コンソールプログラムの実行手順
__.java →[javac(翻訳)]→ ___.class →[java]→実行

実習2.Ⓐウィンドウズアプリケーションの作成・実行
1.次の内容のファイルを作成し、ファイル名 _____.javaで授業フォルダに保存する。注.ファイル名とクラス名は同じにする
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class _____ extends JApplet implements ActionListener {
  //アプレットをフレームに追加して実行。アプレットの場合は不要
  public static void main(String[] args) {
    JFrame jf = new JFrame("タイトル");
    jf.getContentPane().add(new _____());
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jf.setSize(200,100);
    jf.setVisible(true);
  }
  //部品の宣言と生成
  Container cp = getContentPane();//cp は部品を入れるコンテナ
  JLabel jl=new JLabel("Hello!");
  // コンストラクタ:部品の配置とリスナー設定
  public _____() {cp.add(jl,BorderLayout.CENTER);}
  //アクションリスナーの実装
  public void actionPerformed(ActionEvent e) {  }
}

2.コマンドプロンプトを起動し授業フォルダに移動する
>cd z:\javaprog

3._____.java をコンパイルし、実行する
 >javac _____.java
 >java _____
 
アプレットとしてブラウザ上で動作させることもできるが、セキュリティ上の問題から、Javaアプレットを実行させるにはブラウザに特別の設定が必要になっていて、通常、以下の実習はできない。
参考実習3.Ⓐアプレットの作成・実行
上の実習2に続いて
4.次の内容のHTMLファイル sample.html を授業フォルダに作成する
<html>
<head>
  <title>Applet Frame</title>
</head>
<body>
<p>Java Applet</p>
<applet code="_____.class" width="200" height="100"></applet>
</body>
</html>

5.4.で作成したWebページをブラウザで表示させる

ウィンドウアプリケーションの実行手順
_____.java →[javac(翻訳)]→ _____.class →[java]→実行

アプレットの実行手順
_____.java→[javac]→_____.class
sample.html→[ブラウザ]→実行

0.3. NetBeansの使い方

この講義では、前節で説明した手順を省略して簡易なプログラム開発を可能にする統合開発環境NetBeansを用いる。使い方を簡単に説明しよう。

0.ⒶNetBeans+Javaのインストール

NetBeans8.2を自分のパソコンにインストールする場合は、以下の手順に従う。
  1. まずJava SE Development Kit 8u211 又は 8u212をダウンロード・インストールする(自分の環境・OSにあったプロダクトを選択する)
  2. 次にNetBeans 8.2のダウンロードページにアクセスし、適当なバンドルをダウンロード・インストールする
  3. またJDK 8u111 with NetBeans 8.2ではJavaとNetBeansが同時インストールできる
  4. 最新のバージョン(英語版)であればJDK12とAppach NetBeans 11.0の組み合わせでもよい

以下、NetBeans 8.2 の場合で説明するが、NetBeans 11.0 でもほぼ同様である。

新規プロジェクトの作成

1.新規プロジェクトの作成

  1. NetBeansはデフォルトでドキュメント内に NetBeansProjects フォルダを作成する。必要なら授業用フォルダを作成しておく。
  2. [スタート]→[プログラム]→[NetBeans]を起動する
  3. [ファイル]→[新規プロジェクト]で
     カテゴリ=Java (NetBeans 11.0 では Java with Ant)
     プロジェクト=Javaアプリケーション
    を指定して[次へ]
    1. プロジェクト名を適宜指定し
    2. プロジェクトの場所:あれば授業用フォルダを指定し
    3. メインクラスの作成 のチェックを外して【終了】
プログラムの新規作成

2. プログラムの新規作成

  1. [ファイル]→[新規ファイル]で新規ファイルウィザードを開く
  2. 下記のいずれかを選択し[次へ]
    コンソールプログラム:Java→Javaメイン・クラス
    Ⓐウィンドウアプリケーション:Swing GUIフォーム→JFrameフォーム
    ⒶWebページアプリケーション:Swing GUIフォーム→JAppletフォーム
  3. クラス名 を指定して【終了】

3.編集:コンソールプログラム

現れた ソースエディタ 上で、プログラミングする。実行結果は、下部の出力欄に表示される。

注.ソースエディタや出力欄のフォントサイズ等は次の手順で調整できる。フォントには、例えば「MS ゴシック」等の等幅フォントを設定するとよい。
  • ソースエディタ:ツール→オプション→フォントと色
  • 出力欄:ツール→オプション→その他→出力
     出現ウィンドウのフォント欄で【…】ボタンをクリック

4.Ⓐ編集:GUIフォーム(JFrame、JApplet)

タブで デザイン と ソース(エディタ)が切り替えられる。以下の要領で、デザインエディタ上で外観の設計を行い、ソースエディタ 上で イベントハンドラ の応答を記述するが、詳しくはそれぞれの章で解説する。
  1. 部品の配置と属性設定
    1. パレット→必要な部品を選択→フレーム(JFrame) 上でクリック
    2. マウス操作で配置する位置や大きさを調整
    3. プロパティ タブで必要な属性を設定
  2. イベントハンドラの作成
    1. イベントが発生する部品の イベント タブで適切なイベントを選択し
    2. ▼ボタンでハンドラを選択し、現れる ソース エディタ上でプログラミングする
    3. 誤って作成したイベントハンドラの削除は、イベント タブの該当欄を空にする

5.実行、保存

  1. 実行するファイルを右クリックして ファイルの実行 (あるいはShift+F6)を選ぶ
  2. 実行時に自動的に「プロジェクトフォルダ\src」に保存されるので、明示的な保存操作は不要である
  3. Ⓐ実行時(コマンドライン)引数を設定する場合には、プロジェクトの右クリックで現れる プロパティ の 実行 で メインクラス と 引数を指定し、プロジェクトを実行 を選ぶ。
大学環境のように、パソコンの電源OFFで保存内容が消えてしまう場合には、最後にドキュメント内の NetBeansProjects フォルダ(あるいは自分で作成した授業用フォルダ)を USB あるいはクラウド上にコピーしておく必要がある。

6.プロジェクトを開く

一度作成したプロジェクト(ファイル)をNetBeansの再起動時に開くには
  1. USB等に保存したNetBeansProjects(授業用)フォルダをドキュメント等適切な場所にコピーしておく
  2. メニューの ファイル→プロジェクトを開く
  3. 1.でコピーしたフォルダ内に保存してあるプロジェクトフォルダを指定して、【プロジェクトを開く】
  4. プロジェクトウィンドウ(左上)でプロジェクト→ソース・パッケージ→デフォルト・パッケージ を選び、
    現れるプログラムファイルから目的のファイルを選ぶ(ダブルクリック)。

7.Ⓐ単独起動ファイルの作成

4までで作成したアプリケーションはコマンドプロンプトから
>java クラスファイル名
で起動できる。しかし、コンソールアプリケーションならともかくウィンドウアプリケーションを、いちいちコマンドプロンプトやNetBeansを開いたりせずに、ファイルを直接ダブルクリックすることで実行できないと不便である。ここではダブルクリックで単独起動可能なファイル(プロジェクト名.jar)の作成手順を説明しよう。
  1. プロジェクトを右クリックし、プロパティ→実行メインクラスに目的のアプリケーションを指定する。
  2. メニュー→実行→プロジェクトを消去してビルド すれば
  3. プロジェクトフォルダ内の dist フォルダに、プロジェクト名.jarファイルができる

第1章 最初のJavaプログラム

 本章では、最初のプログラムとして、
  1. 標準の出力装置に文字列や値を表示する命令
  2. プログラムにコメントを付加する方法
を学ぶ。

 すでに見たように、Javaプログラムはおおきくコンソールプログラム、ウィンドウアプリケーション、Webアプリケーションの3種類に分けられるが、しばらくは、コンソールプログラムを基本にJavaの文法を学んでゆく。また、Web上でのデータの送受信を伴うプログラムについてはこの授業では扱わない。

1.1.主クラスの構造

例えば、NetBeansで「Java Main Class」を、クラス名「NewMain」で新規作成すると、「NewMain.java」というファイルが作成される。内容は次のようなプログラム(のテンプレート)になり、通常、枠の中に実行したい命令を記入すればよい。
public class NewMain {
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

// TODO code application logic here

} }
 中括弧 {, } は特定の意味をもったブロック(まとまり)の始まりと終りを意味する。ここでは、クラス NewMain (の定義)がその直後の { から始まり、(それに対応する)最後の } で終わる。NewMain の内部にある手続き main は、その直後の { から始まり、(対応する)最後から2行目の } で終わり、その中に書かれた命令(文)が実行される。

1.2.コメント

 コメントはプログラムの命令とは解釈されないので、プログラムに関する説明や覚書を自由に書くことができる。上のプログラムには2種類のコメント(NetBeansでは通常灰色で表示される)がある。
// から行末まで
行の途中からコメント始めたいときや1行だけのコメントに用いる
/* と */ で挟まれた部分
複数行にわたるコメントを入れるときに用いる
 また、プログラムの改善・修正を行う際、修正個所を消してしまうのではなく、コメントにして残しておくことがよく行われる。これをコメントアウトという。
実習.よく起こす間違い: {, }の対応関係と大文字・小文字、全角文字
NetBeansでは、文法エラーを発見した行(ある行ではない)に赤波線が現れ、左端の赤マークにマウスを合わせると、エラーメッセージが表示される。以下の実験をしてみよ
  1. NetBeansで、上記のプログラム中の中括弧( { や } )にカーソルを合わせ、その対応関係を確認せよ
  2. 最初(1行目)の { の直後に } を挿入して、生じるエラーメッセージを確認せよ。この場合、mainの定義がクラス定義の外になったために生じるエラーである
  3. Javaは大文字と小文字を区別する。例えば、String の大文字 S を小文字 s にして現れるエラーメッセージを確認せよ。
  4. 名前(変数名、クラス名)や文字列内では全角文字が使えるが、それ以外ではエラーになる。特に全角の空白は見えないので注意が必要である。全角の空白(カナ漢字変換をONにしてスペースキー)を入れて、現れるエラーメッセージを確認せよ。

1.3.表示

 システムの標準出力装置に文字列を表示させるには
    System.out.print("・・・");
    System.out.println("・・・");

を用いる。後者は・・・を表示した後改行するもので、
    System.out.print("・・・\n");
と同じである(\nは改行記号)。数値の表示も同様で
    System.out.println(4+2*3);
とすれば,その計算結果 10 が表示される(* は掛け算)。
 ここで
  1. Javaでは大文字と小文字を区別するのでSystemのSは大文字にすること
  2. 命令の最後にセミコロン ; を付ける
ことにも注意しよう。

実習.表示命令
下のプログラム(mainメソッドの内部、四角で囲まれた部分だけをNetBeansの対応する場所に記述する)を実行し、結果を確認せよ。また、print命令の括弧内を数式に変える、printをprintlnに変えるなどして、結果を確認せよ。
    public static void main(String[] args) {

System.out.print("こんにちは "); System.out.println("皆さん!");

}

課題

 自分の学籍番号と氏名を表示するJavaプログラム(….java)を統合開発環境NetBeansを用いて作成せよ。

第2章 値の種類と式

 本章では、Java(というよりコンピュータ)が扱う値にはいくつかの(種類)があり、型により(内部表現や)扱いが異なる事を学ぶ。基本的な型には
  1. 整数(int)
  2. 実数(double)
  3. 論理値(boolean)
  4. 文字(char)
がある。他にも多くの型があるが,とりあえず
  1. 文字列(String)
がよく使われる。ここではこれらについて説明する。

実習.
1)以下のプログラムを実行して結果を確認せよ
  public static void main(String[] args) {

System.out.println(2+0);//普通の加算 System.out.println('2'+0);//文字を内部表現(符号)が表す整数として加算 System.out.println("2"+0);//文字列はつなげる

}
2)以下のprint命令の結果を比較し、その理由を考えよ
    System.out.println("2*3="+2*3);
    System.out.println("2+3="+2+3);
結果は 2*3=6 と 2+3=23 となるが、何故だろうか(演算の優先順位が関係する)。また、2+3=5 と表示させるにはどうすればよいか。

2.1.基本的な型とその値

 基本的な値はすべて,コンピュータ内部で定まった大きさのデータとして扱われるので,取り得る値の範囲が次のように決まっている。
  1. intは32ビットで,-231=-2147483648~231-1=2147483647の整数
  2. doubleは64ビットで,有効数字が15~16桁、約±4.94×10-324~±1.80×10308の浮動小数点数
  3. booleanの値はtrueまたはfalse
  4. charは16ビットで半角または全角の文字
 とくに,整数は値の範囲が限られ,実数は精度(有効数字)が限られることを覚えておこう。なお,整数にはintの他にデータサイズの異なる(したがって値の範囲が異なる) byte, short,long があり,実数にはdouble(倍精度)の他にfloat(単精度)があり,必要に応じて使い分けることができる。
 普通に数を表したとき、Javaプログラムでは、小数点がなければ整数あれば実数(の10進数)として認識される。実数は浮動小数点表記もでき,例えば1.23E-31.23e-31.23×10-3と解釈される。また,8進整数は頭に0を付け,16進整数は頭に0X(または0x)を付けて表記する。このように,値は複数の表記を持つことから,表記を値そのものとは区別してリテラルと呼ぶ。

実習.ⒶSystem.out.println()命令を使って以下の値を表示させよ
(1)0123(2)0xab(3)3.14E3(4)5/2(5)5.0/2.0(6)50000*50000
(7)0.00001*10000000000000000.0(8)100000000.0+0.000000001
また、そのような結果になる理由を考えよ。
エスケープシークエンス
\'シングルクォート '
\"ダブルクォート "
\\\記号
\n改行
\r行頭復帰
\tタブ
\bバックスペース
数値以外のリテラルには以下のものがある。
  • 論理値true またはfalseと表記する
  • 文字'(シングルクォート)で括る
    'A'、'山'
  • 文字列"(ダブルクォート)で括る
    "Hello Java"、"こんにちは"
では,文字や文字列を表すときに使う ' や " はどう表せばいいだろうか。これらの特殊な働きをする文字は右表のように直前に\記号を使って表す(エスケープシークエンス)。ただし右表の一部の文字はNetBeans内では有効に働かないことがある。

2.2.変数の宣言と初期値設定

 数学における変数は(未知あるいは不定の)値につける名前であるが、プログラムでいう変数は、値を入れておく箱(に付ける名前)である。例えばx=x+1という式は、数学では無意味だが、プログラムでは変数(箱)xにある値を1増やすという意味になる。本節では、基本的な値を入れる変数とその使い方について学ぶ。
 変数に入れる値の型(種類)をその変数の型という。Javaでは、変数はすべて型を宣言し初期値を代入してからでないと使えないので、変数には宣言した型の値しか入れられない。
 変数の型宣言文は,例えば
    int n;
    double a1, a2, a3;
のように,型名 変数名の並び と記述する。値の代入
    n=100;
    a1=1.23;
    a2=a1+2;
のように,変数名 = 式 と記述する。このとき変数名と式(の値)は原則として型が一致していなければならない(次節の注意書き参照)。
 変数は初期値を設定してからでないと使えないので
    int n=100;
    char a='A', b='x';
のように,型宣言と初期値代入を同時に行なう習慣をつけるとよい。
 変数名を含めてプログラム中の名前は基本的に英字(A~Z、a~z)またはアンダーライン(_)で始まる英数字(A~Z、a~z、0~9)またはアンダーラインの列でなければならない。また、Javaでは大文字と小文字は別の文字として区別される。ただし、最近は環境によって名前に日本語も使えるようになっているので、このテキストでは名前に日本語も用いているがエラーになる場合には適当な英数字列に変えるようにしよう。
問.次の文(命令)を実行し、結果の理由を説明せよ
(1) int x=5, y=2;
     System.out.println(x/y);
(2) double x=5, y=2;
     System.out.println(x/y);

2.3.Ⓐ演算子と式

 加減乗除などの演算を表す記号を演算子という。変数やリテラル(値の表記),関数(多くの関数が用意されている)を演算子で結合してを作ることができる。値には型があるから,型によって使える演算子やその意味,式の値の型が異なる

基 本 演 算 子
+加算,少なくとも一方が文字列のときは連接(つなげる)
-減算
*乗算
/除算,整数同士では小数点以下切捨て
%剰余(割った余り)
条 件 演 算 子(3項演算子)
? : ;論理式?式1:式2; の形。論理式がtrueなら式1,falseなら式2の値
ビ ッ ト 演 算 子
&ビットごとのAND(ともに1なら1、他は0)
|ビットごとのOR(ともに0なら0、他は1)
^ビットごとのXOR(等しいとき0、他は1)
~ビットごとのNOT(0,1の反転)
<<右辺の桁数だけ左シフト。空欄には0が入る。
>>右辺の桁数だけ右シフト。空欄には0が入る。
>>>右辺の桁数だけ右シフト。空欄には先頭ビットの値が入る。
代入演算子:変数へ値を代入する(動作を伴う)
=変数=式。代入式(文)の値は左辺に代入される(右辺の式の)値
・=・は基本およびビット演算子(~を除く)。a・=α は a=a・α と同じ。
++a --a ++a は a=a+1 に同じ。--a は a=a-1 に同じ。
a++ a-- 式の値は a であるが,他は ++a,--a と同じ。
比較演算子:式の値は、成り立てばtrueさもなければfalse
==左辺は右辺と等しい
!=左辺は右辺と等しくない
<左辺は右辺未満
>左辺は右辺より大
<=左辺は右辺以下
>=左辺は右辺以上
論理演算子 論理値から論理値を得る
&&AND(ともにtrueならtrue,他はfalse)
||OR(ともにfalseならfalse,他はtrue)
!NOT

(注)2項演算子の左辺と右辺の型は原則として一致しなければならない。ただし必要ならば(自動的に)、整数値は文字および実数とみなされ、文字値は整数および実数とみなされる。また文字列との連接(+)では,任意の値がその標準的な表記文字列に変換されて連接される。
 さらに,式の前に括弧で括った (型名) を付けると,その型に強制的に変換できる。

2.4.まとめ

本章では、以下のことを学んだ。身についているか確認しよう。
  1. Javaの基本的な値には、整数(int)、実数(double)、論理値(boolean)、文字(char)、文字列(String)の5種類がある。
  2. 整数には表現できる値の範囲があり、割り算は小数点以下切捨てされる
  3. 実数(double)の計算は、有効数字15~16桁の近似計算である
  4. 実数の浮動小数点表示では、m×10nを mEn と表す
  5. 文字は ' で括り、文字列は " で括る
  6. 変数宣言は、 型名 変数名=初期値; とする
  7. 変数は初期値を設定してからでないと使えない
  8. 整数同士の / (除算)は少数点以下を切り捨てる

実習.三角形と円の面積を求める次のプログラムの空欄____を埋めて実行せよ。
public static void main(String[] args) {

//三角形の面積と円の面積 double 底辺=3, 高さ=6, 半径=5; double 三角形の面積=____*____/2, 円の面積=Math.PI*____*____; System.out.println(" 底辺="+____+" 高さ=" +____+" の三角形の面積は"+____); System.out.println(" 半径="+____+" の円の面積は"+____);

}

課題.Ⓐ

(1)次のプログラムを実行し、結果とその理由を考えよ。
public static void main(String[] args) {

System.out.println("整数と文字と文字列の+"); System.out.print(" 2+0 = "); System.out.println(2+0); System.out.print(" '2'+0 = "); System.out.println('2'+0); System.out.print(" \"2\"+0 = "); System.out.println("2"+0); System.out.println("演算の優先順位により+の意味が異なる例"); System.out.println(" 2*3 = "+2*3); System.out.println(" 2+3 = "+2+3); System.out.println("10進、8進、16進数、浮動小数点数"); System.out.print(" 123 = "); System.out.println( 123); //10進数 System.out.print(" 0123 = "); System.out.println(0123); //8進数の123 System.out.print(" 0xab = "); System.out.println(0xAB); //16進数のab System.out.print(" 3.14E3 = "); System.out.println(3.14E3); //3.14×10^3 System.out.println("整数の商と剰余、実数の商"); System.out.print(" 5/2 = "); System.out.println(5/2); //整数の商 System.out.print(" 5%2 = "); System.out.println(5%2); //整数の剰余 System.out.print(" 5.0/2.0 = "); System.out.println(5.0/2.0); //実数の商 System.out.println("整数の範囲を超える計算"); System.out.print(" 40000*50000 = "); System.out.println(40000*50000); System.out.print(" 50000*50000 = "); System.out.println(50000*50000); System.out.println("実数の丸め誤差と情報落ち"); System.out.print(" 0.00001*10000000000000000.0 = "); System.out.println(0.00001*10000000000000000.0); System.out.print(" 100000000.0+0.000000001 = "); System.out.println(100000000.0+0.000000001); System.out.println("整数変数の商とと実数変数の商"); { int x=5, y=2; System.out.println(x/y); } { double x=5, y=2; System.out.println(x/y); }

}

(2)前ページの実習のプログラムを完成させよ。

第3章 プログラムへの入力と例外処理

 本章では、プログラムの実行時に、入力を与える(読み取る)方法を学ぶ。なおファイル入出力については後の章で学ぶ。

3.1.キーボードからの入力

 標準入力装置(キーボード)からの入力をプログラムで読み取るようにするには、
public static void main(String args[]) {

java.util.Scanner 標準入力 = new java.util.Scanner(System.in); System.out.println("生まれた月と日を空白で区切って入力してください"); int 月=標準入力.nextInt(); int 日=標準入力.nextInt(); System.out.println(月+"月"+日+"日生まれですね");

}
のように

java.util.Scanner 標準入力 = new java.util.Scanner(System.in);

で「標準入力」と名前を付けた System.in からのスキャナーを生成し、

int 月=標準入力.nextInt();

で次の入力句(トークン)を必要な変数に必要な型の値として読み取る。
 読取メソッドは、整数、実数、論理値、文字列に対応したものがあり、それぞれ
  • int 整数 = 標準入力.nextInt();
  • double 実数 = 標準入力.nextDouble();
  • boolean 論理値 = 標準入力.nextBoolean();
  • String 文字列 = 標準入力.next();
のように用いる。

実習.
前回作成した、三角形と円の面積を計算するプログラムに、底辺と高さ、半径をキーボードから入力できるようにせよ。

3.2.Ⓐコマンドラインからの入力

 コンソールプログラムに対して入力を与える方法に、実行時に引数(パラメータ)として与える方法もある。
    public static void main(String[] args) { ・・・ }
となっているとき、実行時引数は
     args[0], args[1], ..., args[args.length-1]
に順に文字列として格納されるので、これらをプログラム中で利用できる。実行時引数は空白で区切って与える。また、args.length は引数の個数である。NetBeansでは引数を与えて実行できるのはプロジェクトの主クラスだけなので、引数を与えたいときは、
  1)プロジェクトの右クリックで現れるプロパティの「実行」で
  2)主クラスとして実行するプログラムを指定し
  3)必要な引数(入力)を指定し、
  4)プロジェクト実行を選ぶ。

3.3.Ⓐ例外処理

入力処理などでは、想定外の入力等、読み込みに関わって生じる可能性のあるエラーの対策を講じなければならない。これを例外処理といい、次の形式をとる。
try {
   //例外(エラー)が発生する可能性のある部分
} catch (例外のクラス 例外) {
   //例外に対する処理
}
こうすると、tyr部で例外(エラー)が発生したとき(だけ)catch部の例外処理が行われ、その後、try-catch部の次から計算を継続する。
 例外はその種類(クラス)によって、処理を変えることもできる。ここでは、読取時のエラーと0による割り算のエラーを処理してみよう。実は、以下の実習でも分かるように、キーボードかrなお読み取りや割り算は通常、例外処理を書かなくても実行可能で文法(コンパイル)エラーにはならないが、後で学ぶファイル入出力では例外処理を書いていないと文法エラーになる。
 以下のプログラムは100を入力整数で割るプログラムである。
例外処理のないプログラム

java.util.Scanner 標準入力=new java.util.Scanner(System.in); int n=標準入力.nextInt(); int p=100/n; System.out.println("100/"+n+"="+p);

例外処理をしたプログラム

java.util.Scanner 標準入力=new java.util.Scanner(System.in); int n=1, p=100;//nやpの初期値設定 try{ n=標準入力.nextInt(); //非整数入力の例外発生 p=100/n;//n=0による除算の例外発生 } catch(java.util.InputMismatchException 例外){//不正入力の例外 System.out.println(標準入力.next()+"は不正。初期値で続行"); } catch(java.lang.ArithmeticException 例外){//不正計算の例外 System.out.println(例外.toString()+" pは初期値のまま"); } System.out.println("100/"+n+"="+p);


注.例外処理を行うと、例外(エラー)が発生しても計算は継続されるので、使用される変数に対しては、デフォルトの初期値を設定しておく必要がある。

実習.Ⓐ
1.例外処理のないプログラムの動作を様々な入力 1、2、0、0.0、one で調べ、どのような例外が発生するか確認しよう。
2.例外処理をしたプログラムの動作を1.と同じ入力で調べよう。 3.3.1節の実習で作成したプログラムに例外処理を加えよう。teihenn, takasa, hankei の初期(デフォルト)値は適当でよい。

3.4.まとめ

本章では主に、キーボードからの、整数、実数、文字列の入力と例外処理について、学んだ。

第4章 条件分岐

 この章では、IF文とELSE文を組み合わせて、条件によって処理を変えるプログラムの書き方を学ぶ。

4.1.IF文とELSE分

    if (条件式) {・・・}

と書くと、「条件式が成り立つときだけ {…} の内部を実行せよ」という意味になる。条件式は必ず括弧の中に入れなければならない。

    else {・・・}

の形式で、IF文の直後に用いる。「直前のIF文の条件式が成り立たなければ、{・・・}の内部を実行せよ」という意味になる。
注.{・・・}の中が1文だけのときは、中括弧 { と }を省略してもよい。

4.2.複数の条件による分岐   

    if (条件1) {処理1}
    else if (条件2) {処理2}
    else if (条件3) {処理3}
        ・・・
    else if (条件n) {処理n}
    else {処理0}

と書くと、
 条件1が成り立てば処理1行い、
 そうでなくて(条件1が成り立たず)条件2が成り立てば処理2を行い、
 そうでなくて(条件1,2が成り立たず)条件3が成り立てば処理3を行い、
    ・・・
 そうでなくて(条件1,…,n-1が成り立たず)条件nが成り立てば処理nを行い、
 そうでなければ(条件1,…,nが成り立たなければ)処理0を行なう
という意味になる。プログラムではこの形で使うことが多い。

4.3.条件式

A==BAとBが等しい
A!=BAとBが等しくない
A<BAはBより小
A>BAはBより大
A<=BAはB以下
A>=BAはB以上
 条件式の基本は右表下のような二つの式の値を比較する式である。さらに、条件式は論理演算かつ(&&)、または(||)、でない(!)を使って組み合わせることができる。その際、分かりやすさも考慮して適宜括弧 (, ) や半角空白を補うとよい。

例えば整数変数 月 と 日 が与えられたとき、月 日 が3月21日から4月19日までの日付であることを表す条件式は、 「月 が 3 と等しくて 日 が 21 以上であるか、月 が 4 と等しくて 日 が 19 以下である」と表現すれば
    (月==3 && 21<=日)||(月==4 && 日<=19)
となる。また、3月が31日までであることや、4月が1日から始まることを考慮すれば、
    (月==3 && 21<=日 && 日<=31)||(月==4 && 1<=日 && 日<=19)
と書ける。
問.Ⓐプログラムの違い(}の位置)に注意して表の空欄を埋めよ
ヒント:2段目のように字下げをすると、ブロック構造(括弧の対応関係)がわやりやすいだろう。
(1) (2) (3)
}の位置 if (条件1) {処理1}
if (条件2) {処理2}
else {処理3}
if (条件1) {処理1
if (条件2) {処理2}}
else {処理3}
if (条件1) {処理1
if (条件2) {処理2}
else {処理3}}
整形して表示 if (条件1) {処理1}
if (条件2) {処理2}
else {処理3}
if (条件1) {
 処理1
 if (条件2) {処理2}
}

else {処理3}
if (条件1) {
 処理1
 if (条件2) {処理2}
 else {処理3}
}
各処理をする条件 if (条件1) {処理1}
if (条件2) {処理2}
if (!条件2) {処理3}
if (____) {処理1}
if (____) {処理2}
if (____) {処理3}
if (____) {処理1}
if (____) {処理2}
if (____) {処理3}
条件1 条件2 実行される処理とその順序
true true 処理1 処理2
true false 処理1 処理3
false true 処理2
false false 処理3
実習.Ⓐ
以下は(1)の答えを確認するプログラムである。(2)または(3)について、同様にプログラムを作成し、前問の答えを確認せよ。
public static void main(String[] args) {

boolean 論理値[]={true,false}; System.out.println("条件1 条件2 (1)"); for(boolean 条件1:論理値) for(boolean 条件2:論理値){ System.out.printf("%5b %5b ",条件1,条件2); /***********************************************/ if (条件1) {System.out.print(" 処理1");} if (条件2) {System.out.print(" 処理2");} else {System.out.print(" 処理3");} /***********************************************/ System.out.println(); } System.out.println("---------------結果は同じ---"); for(boolean 条件1:論理値) for(boolean 条件2:論理値){ System.out.printf("%5b %5b ",条件1,条件2); /***********************************************/ if (条件1) {System.out.print(" 処理1");} if (条件2) {System.out.print(" 処理2");} if (!条件2) {System.out.print(" 処理3");} /***********************************************/ System.out.println(); }

}

4.4.まとめ

本章では以下のことを学んだ。身についているか確認し、課題に挑戦しよう。

文法事項
  1. 条件分岐は、if (条件式) {・・・} と else {・・・} を組み合わせて記述する
  2. 複数の条件による場合分けの基本形
         if (条件式) {・・・}
         else if (条件式) {・・・}
         else if (条件式) {・・・}
              ・・・
         else if (条件式) {・・・}
         else {・・・}
    
  3. {・・・}の中身が1文だけのときは中括弧{、}で括らなくてもよい
  4. 値を比較する演算子には、==、!=、<、<=、>、>= がある
  5. 条件式を組み合わせる演算子には、&&、||、! がある
  6. 条件式は括弧(、)で括る


補足事項

 本節の課題プログラムでは、System.out.println(文字列)、Math.random()、などの関数を利用している。これらの詳細な意味については講義内で触れるが、頭についているSystemMath等の名前は、ライブラリ(関数等を集めているクラス)の名前である。これらのクラスにどのような関数が用意されているか、他にどのようなクラスがあるか、またこれらの関数の働きについては、Javaのマニュアルページを参照せよ。
 また、(int)のように、式の前に括弧で括った (型名)を付けると,その値の型に強制的に変換できる。

課題(3,4章)

以下のプログラムを作成せよ
1.3.1.節の実習で作成したプログラムに例外処理を付け加えたプログラム(….java)
2.4.3条件式の実習で作成したプログラム
3.以下の、キーボードから誕生日を受け取って、星座を出力するプログラムを完成させよ。またこのプログラムは不適切な日付への対応を考慮していないので、下記(1)、(2)の修正を加えたプログラムを作成せよ。
(1)4 31 (4月31日)のようなありえない日付を受け付けない
    ヒント:前ページのプログラムチップス
(2)整数でない入力に対する例外処理

/*
牡羊座  3/21-4/19  牡牛座  4/20-5/20 双子座 5/21- 6/21 蟹座  6/22- 7/22
獅子座  7/23-8/22  乙女座  8/23-9/22 天秤座 9/23-10/23 蠍座 10/24-11/22
射手座 11/23-12/21 山羊座 12/22-1/19 水瓶座 1/20- 2/18 魚座  2/19- 3/20
*/
public static void main(String args[]) {

java.util.Scanner 標準入力 = new java.util.Scanner(System.in); System.out.println("生まれた月と日を空白で区切って入力して下さい"); int 月 = 標準入力.nextInt(), 日 = 標準入力.nextInt(); System.out.println(月+"月"+日+"日生まれですね"); String 星座=null; if (月== 3 && 21<=日 || 月== 4 && 日<=19) 星座="牡羊"; else if (月== 4 && 20<=日 || 月== 5 && 日<=20) 星座="牡牛"; else if (月== 5 && 21<=日 || 月== 6 && 日<=21) 星座="双子"; //・・・ if(星座 != null){ System.out.print("あなたは" + 星座 + "座で"); String 性格[]={"落ち着いた", "明るい", "人に好かれる"}; System.out.println(性格[(int)(性格.length*Math.random())]+"性格です"); } else System.out.println("誕生日を入れなおしてください");

}

面接授業提出課題1

次のどちらかのプログラムを提出せよ。
提出期限:1週間以内
提出方法:yamasaki.hideki@ouj.ac.jpへのメール内への記述(コピペ)
メールタイトル:Javaプログラミング入門提出課題1
メール内容:学生番号、氏名、プログラムの説明(プログラム中に記入してよい)
  1. 入力として底辺と高さ、半径を受け取り、三角形と円の面積を出力するプログラム
  2. 入力として誕生日を受け取り、星座を出力するプログラム

第5章 繰り返し

繰り返しこそコンピュータが最も得意とするところである。プログラムを書けば、コンピュータは単調な繰り返し作業も厭わず、かつ高速にこなす。

5.1.FOR文

for (初期設定;繰り返し条件;更新処理) {・・・}

と書くと、
  ①「初期設定」を実行
  ②「繰り返し条件」を調べ、YESならば③へ、NOならばこのfor文を抜ける
  ③ 繰り返し部分 {・・・} を実行
  ④「更新処理」を実行して②へ
という意味になる。for 文の様々な使い方を学習しよう。
注.{・・・}の中が1文だけのときは、中括弧 { と }を書かなくてもよい。

5.2.逐次的な繰り返し

 ある処理を n 回繰り返すには、

  for (int i=1; i <= n; i++) {i 回目の処理}

とする。このような i を(for 文の)制御変数と呼び通常整数型(int)変数を用いる。

*
**
***
****
*****
例題1.for文を使って、右図ののように1個ずつ増える*の列を出力させてみよう。まず、
    ***...*
のように「*」をj個表示して改行する」には、
 for (int i=1; i <= j; i++) System.out.print("*");
 System.out.println();
とする。次に、「『j 行目に * を j 個表示させる』ことを、j=1, 2, …, n に対して行なわせる」には、
 for (int j=1; j <= n; j++) {
   for (int i=1; i <=j; i++) System.out.print("*");
   System.out.println();

 }
これをさらにnの値をキーボードから読み取るプログラムにするには、関数mainの中に以下を入れればよい。

 java.util.Scanner 標準入力 = new java.util.Scanner(System.in);
 int n = 標準入力.nextInt();

 for (int j=1; j <= n; j++) {
   for (int i=1; i <=j; i++) System.out.print("*");
   System.out.println();

 }


実習(発展).Ⓐ以下の出力を持つプログラムを作成せよ。
a
ab
abc
abcd
abcde
ヒント:文字'a'から順にj文字出力させるには
  for (char c='a';c<'a'+j; c++) System.out.print(c);
とする。ここで、繰り返し条件が c<'a'+j; <= ではなく < である理由を考えよ。

実習.サイズ(行数)nに対し以下の図形を出力するプログラムを書け
....*....
...***...
..*****..
.*******.
*********
ヒント: j 行目を作るには、(n-j)個の.(ピリオド)、(2*j-1)個の *、(n-j)個の. を出力してから改行する。

5.3.条件を満たす値(整数)を求める

ある条件をみたす(整数)値 k を求めたいことはよくある。その場合、
  int k=最初の候補;
  for ( ; k が条件を満たさない; k=次の候補);
とすれば、最初に見つかった整数が k の値として得られる。

例題2.与えられた整数 n (n≧2)の最少の約数(素因数)を求めるプログラム

 java.util.Scanner 標準入力 = new java.util.Scanner(System.in);
 int n = 標準入力.nextInt();
 int 素因数 = 2;
 for ( ; n % 素因数 != 0; 素因数++);
 System.out.println(素因数);

 Ⓐしかし、最初に 素因数=2 でチェックした後は、素因数 が√nまでの奇数のときだけ調べれば十分だから、

 java.util.Scanner 標準入力=new java.util.Scanner(System.in);
 int n=標準入力.nextInt();
 int 素因数=2;
 double 平方根n=Math.sqrt(n)+1;
 if (n%素因数!=0)
   for (素因数=3;(n%素因数!=0)&&(k<平方根n); 素因数+=2);
 if (素因数>=平方根n)  素因数=n;
 System.out.println(素因数);

とすれば、計算時間が(nから(√n)/2の)節約になる。

コラム. 無限ループ 重要!
例題2.のプログラムは、 n=1 を入力したとき、n を 素因数(≧2)で割った余り n%素因数 が 0 になることはないから、for文を無限に繰り返し実行してしまうという重大な欠点がある。for文を使うときには無限ループに入ってしまうことのないよう、十分に注意してプログラムしなければならない。
 万が一、プログラムが無限ループに入ってしまったと思われるときは、
(1)NetBeans内であれば、メニューの実行→構築・実行の停止
(2)Ctrl+Alt+Delタスクマネージャーでプロセスjava.exeを終了
のどちらかの方法で停止させる。

コラム.宣言の有効範囲 重要!
変数の宣言(int j, int 素因数 など)は、Javaでは通常初期値設定とともに行われるが、5.2.の例題では、for文の初期値設定部分に、5.3.の例題では for 文の前にある。この違いにはどのような意味があるのだろうか。
 実は宣言の有効範囲は、宣言のある位置から宣言のある文やブロック({と}で囲まれた部分)の終わりまでである。したがって、5.2.の例題では宣言された変数は for 文の中だけで(制御用に)しか使えない。一方、5.3.の例題では、for 文で求めた 素因数 の値が for 文の後でも使える。

実習.与えられた正整数 n が素数か否かを判定するプログラムを書け
ヒント:n の素因数を求めて、素因数が n に等しいか否か調べる。

5.4.Ⓐ一般的な繰り返し

一般にある条件が成り立っている間、処理{・・・}を繰り返すには、
  for ( ; 繰り返し条件; ) {・・・}
と書く。この形はよく使われるので、while文を使って
  while (繰り返し条件) {・・・}
と書くことができる。また、do-while文
  do {・・・}
  while (繰り返し条件);
は、処理{・・・}を行ってから繰り返し判定を行うので
  for ( ; ; ) {・・・
    if (!繰り返し条件) break;
  }
と等しい。ここでbreak文は繰り返しを終了することを意味する。

実習.正整数 n の素因数分解を求める
与えられた正整数 n の素因数分解を求めるには、
 for ( ; n>1; ) {
   n の 素因数 を求めて
   素因数 を表示する
   n /= 素因数;
 }
とすればよい。プログラムを作成せよ。

実習(発展).
1.上の実習の素因数分解プログラムを、例えば12と入力したときに
    12 = 2*2*3
と出力されるようにせよ。
2.そのプログラムをwhile文を用いて書き換えよ

5.5.まとめ

本章では以下の事を学びプログラムを作成した。身についたか確認しよう。

文法事項
  1. for文の形は、
     for (初期設定;繰り返し条件;更新処理) {・・・}
  2. ある処理を n 回繰り返すには、
     for (int i=1; i <= n; i++) {i 回目の処理}
  3. ある条件をみたす(整数)値 k を求めるには、
      int k=最初の候補;
      for ( ; k が条件を満たさない; k=次の候補);
  4. 条件が成り立っている間、処理を繰り返すには、
     for ( ; 条件; ) {処理}

プログラムチップス
  1. 例えば、ピリオド.をj-1個並べた後ろにアスタリスク*を2j-1個並べた行を表示するには
     for(int i=1; i<=j-1; i++) System.out.print('.');
     for(int i=1; i<=2*j-1; i++) System.out.print('*');
     System.out.println();
  2. 例えば、n の最小約数(素因数)を求めるには、
     int 素因数 = 2;
     for ( ; n % 素因数 != 0; 素因数++);
  3. 例えば、nの素因数を小さいほうからリストアップする<には、
     for ( ; n>1; ) {
       int 素因数 = 2;
       for ( ; n % 素因数 != 0; 素因数++);
       System.out.println(素因数+" ");
       n /= 素因数;
     }
    注.最後は、n/=素因数 の後 n の値が 1 になって終了する

課題

以下のプログラムを作成せよ
1.5.2の実習で作成したプログラム
2.5.3の素数判定プログラム
3.5.4の素因数分解プログラム

第6章 配列

数学では a1, a2, … 等の添え字付き変数列がよく用いられる。このような変数列のことを配列、配列を構成する各変数を配列要素と呼び、Javaではa[1]、a[2]、のように表す。本章では配列の利用法を学ぶ。
配列要素(String)初期値
性格[0]"落ち着いた"
性格[1]"明るい"
性格[2]"人に好かれる"

6.1.配列の宣言

(1)配列をその初期値とともに宣言するには、例えば
   String 性格[]={"落ち着いた","明るい","人に好かれる"};
のようにする。このとき 性格[0]~性格[2] までの配列要素(文字列型変数)が用意され、右表のようになる。添え字の値は 0から始まる事に注意せよ。
 一般には、
   要素の型名 配列名[]= {初期値0,初期値1,・・・,初期値n-1};
とすると、
   配列名[0]、配列名[1]、…、配列名[n-1]、
という指定された型のn個の要素変数がその初期値とともに用意される。

配列要素(int)デフォルト値
a[0]0
a[1]0
a[99]0
(2)初期値を陽に設定せず、配列だけを用意するには、例えば
   int a[]=new int[100];
とする。このとき、右表のように、100個の配列要素(int型変数)が用意され、デフォルト値が設定される。一般には、
   型名 配列名[]= new 型名[要素数];
とすると、
   配列名[0]、配列名[1]、・・・、配列名[要素数-1]、
という指定された型の要素変数が用意され、型に応じたデフォルト値が設定される。

これらの定義からも分かるように、配列を構成する配列要素は、すべて同じ型の変数になる。また、配列の長さ(要素数)は 配列名.length で取得することができる。

6.2.配列(要素)に対する逐次処理

配列の各要素に一律にある処理(操作)を行ないたいときは、
   for (int i=0; i < 要素数; i++) {配列名[i]に対する処理}
とすればよい。以下、与えられたデータの平均値を求めるプログラムを作成してみよう。

java.util.Scanner 標準入力=new java.util.Scanner(System.in); double データ[]=new double[100];//データ配列 int データ数=10; //データの取り込み for (int i=0; i<データ数; i++) データ[i]=標準入力.nextDouble(); //和(データ[0]+データ[1]+・・・+データ[データ数-1])の計算 double 和=0.0; for (int i=0; i<データ数; i++) 和+=データ[i]; //平均値の表示 if (データ数>0) {//データ数が0のときは実行しない double 平均値=和/データ数; System.out.println("平均値="+平均値); }

6.3.配列へのキーボード入力

 6.2の例題では、例えば n=10 といったあらかじめ定められた数のデータしか扱えない。ここでは、読み込むデータ数を実行時に変えられる3通りの方法を紹介する。

(1)データ数をキーボードから入力:6.2の例題にデータ数のキーボード入力を付加し以下のようになる。

 java.util.Scanner 標準入力=new java.util.Scanner(System.in);
 System.out.println("データ数?");
 int データ数=標準入力.nextInt();
 double データ[]=new double[データ数];
 System.out.println("データ?");
 for (int i=0; i<データ数; i++) データ[i]=標準入力.nextDouble();
(2)終了を表す値を入力する:例えばデータはすべて0以上と仮定して、-1が入力されたら終了とする。

java.util.Scanner 標準入力 = new java.util.Scanner(System.in);
double データ[]=new double[100];
int データ数=0;
System.out.println("データ(終了=-1)?");
for (double 入力値;
   (入力値=標準入力.nextDouble())!=-1; //入力値 が終了値でない間
   データ[データ数++]=入力値); //データ[データ数]に入力値を代入しデータ数を1増やす

.式n++自体の値は、1増える前のnの値であり、式++nの値は1増えた後の値n+1である。

(3)Ⓐ例外処理の利用:例えば文字zが入力されたら終了とする。

java.util.Scanner 標準入力 = new java.util.Scanner(System.in);
double データ[]=new double[100];
int データ数=0;
System.out.println("データ(終了=z)?");
for (double 入力値; ;){ 
   try{入力値=標準入力.nextDouble();
      データ[データ数++]=入力値;}
   catch(Exception 例外){
      if (標準入力.next().charAt(0)=='z') break;
      else System.out.println("入力し直して下さい");}
}   

break は、for文やwhile文から抜け出る命令である
実習.偏差値の計算
6.2のプログラムに、読み込むデータ数を実行時に変えられる機能と、標準偏差を求めて入力値(100点満点の点数)それぞれの偏差値を求める機能を追加せよ。
ヒント:偏差(平均値との差)の2乗の平均を分散といい、分散の平方根を標準偏差という。偏差値は平均値が50、標準偏差が√100=10なるように標準化した値を言い、データ[i]の偏差値[i]=(データ[i]-平均値)/標準偏差*10+50である。以下のプログラム(の一部)の空欄を埋めて、6.2のプログラムに適切な位置に挿入せよ。

//標準偏差の計算
  //i=0,1,・・・,データ数-1に対する(データ[i]-平均値)*(データ[i]-平均値)の和の計算
  double 偏差2乗和=0.0;
  for (______; ___; ___) 偏差2乗和+=______________________;
  //偏差2乗和の平均(偏差2乗和/データ数)の平方根をとる
  double 標準偏差=Math.sqrt(_________);
//偏差値配列の計算
  double 偏差値[]=new double[100];//配列を用意
  for (int i=0; i<データ数; i++){
    //偏差値[i]=(データ[i]-平均値)/標準偏差*10+50
    偏差値[i]=_______________________;
    //データ[i]と偏差値[i]を表示
    ________________________________;
  }
a[・][0]a[・][1]a[・][2]
a[0]ABC
a[1]abc
a[2]012

6.4.多次元配列

添え字が2個以上であるような多次元配列は配列の配列として[]を次元数個並べて次のように宣言される。例えば
   char a[][]={{'A','B','C'},{'a','b','c'},{'0','1','2'}};
とすると、
   a[0]={'A','B','C'}, a[1]={'a','b','c'}, a[2}={'0','1','2'}
なので右上のような配列が用意される。
また、
   int a[][]=new int[100][100];
とすれば、a[0][0]~a[99][99]の100×100配列が用意される。

例えば、以下は(n-1)×(n-1)の掛け算の表を作成する。
 java.util.Scanner 標準入力=new java.util.Scanner(System.in);
 int n=標準入力.nextInt();
 int 掛算表[][]=new int[n][n];
 for (int i=0; i<n; i++) for(int j=0; j<n; j++)
   掛算表[i][j]=i*j;
 for (int i=0; i<n; i++){
   for(int j=0; j<n; j++) System.out.printf(" %3d",掛算表[i][j]);
   System.out.println();
 }

実習.
上のプログラムを組み込んだアプリケーションを作成せよ。その際、
   System.out.printf(" %3d",掛算表[i][j]);
   |   2   3   4   5   6   7   8   9
-------------------------------------
 2 |   4   6   8  10  12  14  16  18
 3 |   6   9  12  15  18  21  24  27
 4 |   8  12  16  20  24  28  32  36
 5 |  10  15  20  25  30  35  40  45
 6 |  12  18  24  30  36  42  48  54
 7 |  14  21  28  35  42  49  56  63
 8 |  16  24  32  40  48  56  64  72
 9 |  18  27  36  45  54  63  72  81
がどのような働きをするか、調べてプログラムにコメントとして記入せよ。
 Ⓐ余裕があれば、入力 n=10 のとき右のように出力されるようにせよ。なお、NetBeansの出力用フォントが等幅フォントでないと表示がずれる。その場合は、ツール→オプション→その他 でフォントの【…】をクリックして、例えば「MS ゴシック」等の等幅フォントを設定するとよい。

6.5.Ⓐ応用例題1:文字の出現頻度

 ここでは、英文テキスト中の文字の出現頻度を数える例題を考えよう。英数字(半角文字)は、1バイト文字で0~255の整数と同一視できる(値の種類と式の章を参照)ので、配列の添え字として利用できる。そのことを見るために、まず以下のプログラムを実行してみよう。
  int 頻度[]=new int[256];
  頻度['a']=3;
  System.out.println(頻度['a']);

 キーボードから入力した 文字列 中のアルファベットの出現頻度を数えるプログラムは以下のようになる。

int 頻度[]=new int[256];//文字の出現頻度を格納する配列 java.util.Scanner 標準入力 = new java.util.Scanner(System.in); //空白で区切られた 文字列 を読み取って処理。".."で終了 for (String 文字列; !"..".equals(文字列=標準入力.next()); ){ System.out.println(文字列);//文字列 を改行表示 for(int i=0; i<文字列.length(); i++) 頻度[文字列.charAt(i)]++;//出現頻度のカウント } //出現頻度の表示:小文字 for(char 文字='a'; 文字<='z'; 文字++) System.out.print("  "+文字+":"+頻度[文字]); System.out.println();


実習.上のプログラムに、以下の修正を加えよ
(1)テキスト中の大文字各々の出現頻度を表示するプログラムを追加せよ。
(2)テキスト中の各々の大文字+小文字の出現頻度を表示するプログラムを追加せよ。

6.6.Ⓐ応用例題2:Eratosthenesの篩

 エラトステネスの篩(ふるい)は、ある数nまでの素数の一覧表を求める古くから知られるアルゴリズムである。下表のように、2からn(=15)までの欄を用意し、そこに素数(かもしれない事)を意味する〇を入れておく。小さい方から順に、まだ選ばれていない素数i()を選んだらその倍数を消していく(×)。こうして合成数を篩い落とせば、素数だけが残る。
 表のn+1(=16)番目は、番兵と言って、選ばれていない次の 素数 を探すときに表の範囲を越えてエラーになることを防ぐためのプログラミング上の工夫である。これがないと実習のプログラムで何が起きるか確かめてみよ。

参考.15以下の素数を求めるエラトステネスの篩の計算過程
i23456789 10111213141516
2 × × × × × ×
3 ×× ×× ×× ××
5 × ×××× ×××
7 ×× ××××× ×
11 ×× ××× ×××
13 ×× ×××× ××
16 ××× ×××××

実習(発展).空欄____を埋めて完成させよ。
また、プログラムに番兵が必要な理由をコメントとして付けよ。

int n=100; //素数か否かを示す 篩[0]~篩[n+1] の論理値(boolean)型配列を定義 //篩[n+1]は番兵。 篩[0],篩[1] は使わない boolean 篩[]=new boolean[n+2]; // 初期設定:篩[2]~篩[n+1]をすべてtrue〇にする for(int i=2; i<=n+1; i++) 篩[i]=____; //素数=2 から、素数<=n の間、以下の1. 2. 3. を繰り返す for(int 素数=2; 素数<=n; ){ //1. 素数 を出力 System.out.print(____); //2. 倍数=素数*素数 から 倍数<=n の間 素数 ごとに 篩[倍数]=false×とする for(int 倍数=___; ____; 倍数+=素数) 篩[倍数]=_____; //3. 篩[素数]==true である次の 素数 を求める for(素数++; !篩[素数]; 素数++); }

6.7.まとめ

本章では以下の事を学び、プログラムを作成した。

文法事項
  1. 配列の添え字の値は0から始まる
  2. 配列要素の値を明示して(1次元)配列を定義するには  型名 配列名[]= {初期値0,初期値1,・・・,初期値n-1};
  3. 値を明示せず、デフォルトの初期値で(1次元)配列を定義するには
     型名 配列名[]=new 型名[要素数];
    注.この配列の最終要素は、配列名[配列要素数-1]である。
  4. 2次元以上の高次元配列を定義するには、配列を要素とする配列を定義する
  5. 配列要素の値を明示して2次元配列を定義するには、
     型名 配列名[][]={
      {初期値[0][0],初期値[0][1],・・・,初期値[0][n0-1]},
      {初期値[1][0],初期値[1][1],・・・,初期値[0][n1-1]},
         ・・・,
      {初期値[m][0],初期値[m][1],・・・,初期値[0][nm-1]}};
  6. 値を明示せず、デフォルトの初期値で2次元配列を定義するには
     型名 配列名[][]=new 型名[要素数1][要素数2];
  7. 1次元配列の各配列要素を順に処理する基本形
      for (int i=0; i < 要素数; i++) {配列名[i] に対する処理}
  8. 2次元配列の各配列要素を順に処理する基本形
      for (int i=0; i < 要素数1; i++){
        for (int j=0; j < 要素数2; j++) {配列名[i][j] に対する処理}
      }
  9. 書式を指定して標準出力に表示する命令は、
      System.out.printf(書式指定文字列,変数1,変数2,…,変数n);
    である。書式指定文字列について詳しくはネットで調べるかこちらを見よ
  10. 文字型の値は、その内部表現が表す2進整数値と同一視できるので、配列の添え字に使える
  11. 文字列 s1 と s2 が等しいか否かの判定に == は使えず、s1.equals(s2)とする。charAt()等の文字列関連メソッドの詳細はネットで調べるかこちらを参照するとよい
プログラムチップス
  1. データ数 を読み込んだ後、個数分のデータを順に処理する
     java.util.Scanner 標準入力=new java.util.Scanner(System.in);
     int データ数=標準入力.nextInt();
     for (int i=0; i<データ数; i++) {
       double データ=標準入力.nextDouble();
         データ の処理
     }
  2. 終了値が入力されるまで、データを読み込んでは処理する
     java.util.Scanner 標準入力=new java.util.Scanner(System.in);
     int データ数=0;
     for (double データ;(データ=標準入力.nextDouble())が終了値でない; データ数++){
       データ の処理
     }
  3. 第0項から始まる各項の 和 を求める
     double 和=0;
     for (int i=0; i<項数; i++) 和+=第i項;
  4. n の素因数を小さいほうからリストアップする
     for ( ; n>1; ) {
       int 素因数= 2;
       for ( ; n % 素因数 != 0; 素因数++);
         素因数 を表示する
         n /= 素因数;
     }
    注.最後は、n/=kの値が1になって終了する
  5. 半角(1バイト)文字を添え字に使う配列 a
     int a[]=new int[256];
  6. 文字変数 c の値を小文字から大文字に変換する式は、c-'a'+'A'

課題

以下のプログラム(….java)を作成せよ。
1.入力された点数それぞれの偏差値を求めるプログラム
2.入力された数nまでの掛け算表を表示するプログラム
3.文字の出現頻度を求めるプログラム

第7章 Ⓐクラス・オブジェクト

 JAVAでのアプリケーション開発にはオブジェクト指向プログラミングの基本概念であるオブジェクトやクラスの理解が欠かせない。説明を避けてきたが、実はこれまでもクラスやオブジェクトを陰に陽に利用してきている。本章では、少し詳しく学んでいこう。
 オブジェクト指向では、アプリケーション(システム)の基本構成要素は状態機能とを持つオブジェクトであると考える。オブジェクトの状態とは、そのオブジェクトのプロパティ(属性)の値であり、機能とはそのオブジェクトが受け取れるメッセージ(命令)、あるいはそのオブジェクトが実行できるメソッド(関数)である。
 しかし、オブジェクトがどのようなプロパティとメソッドを持つかは、オブジェクトの種類(、タイプ)によって異なる。オブジェクトの型を規定するものをクラスという。

7.1.クラス定義とオブジェクト生成

 クラスオブジェクト
名前挨拶ロボットケン
属性挨拶文よろしく
メソッド挨拶挨拶
set挨拶(s)set挨拶(s)
コンストラクタ挨拶ロボット――
 例えば、ケン という名前の挨拶ロボットを(プログラム内で)実現することを考えてみよう。ここで ケン がオブジェクトにあたり、挨拶ロボットが(ケンが属す)クラスにあたる。挨拶ロボットは属性として「挨拶文」を持ち、「挨拶」というメッセージ(命令)を受け取ると挨拶文を返し、「set挨拶(s)」というメッセージを受け取ると自分の挨拶文を s に設定する。
 すなわち、クラスは、そのクラスのオブジェクトがどのような属性を持ちどのようなメソッドを持つかを規定したものであり、オブジェクトを生成するコンストラクタというクラス名と同じ名前のメソッドを持つ。一方、オブジェクトはそのクラスのインスタンス(実例)で、属性のそれぞれに具体的な値を定めたものである。

挨拶ロボット のクラスを定義すると以下のようになる。
public class 挨拶ロボット {

//属性・プロパティ private String 挨拶文="よろしく"; //デフォルトの挨拶文 //メソッド public void set挨拶(String s) {挨拶文=s;}//挨拶を s に設定 public String 挨拶() { return 挨拶文; } //挨拶を返す //コンストラクタ(記述を省略しても同じ) public 挨拶ロボット() { super(); }

・・・ }

 Robot クラスのオブジェクトkenを生成し挨拶させるには、mainメソッドで次のように記述する。
public static void main(String[] args) {

挨拶ロボット ケン = new 挨拶ロボット();//オブジェクト ケン を生成 System.out.println(ケン.挨拶());// ケン の挨拶を表示

}

実習.以下の手順にしたがってプログラム(ファイル)を作成し結果を確認せよ。
1.ファイル名 挨拶ロボット で 挨拶ロボット のクラスを定義し、
2.挨拶ロボット ケン を生成し、ケン が挨拶をすることを確認する
3.ケン に新たな挨拶 s を教え(set挨拶(s))、教えられた挨拶をすることを確認する
 クラスはまた、既に定義したクラスを継承(拡張)して定義することができる。このとき元のクラスをスーパークラス、継承して定義されるクラスをサブクラスという。挨拶ロボット クラスをもとに、主人属性を追加し、主人名を設定し(教え)たり、挨拶に主人名を加えたりといった、属性の追加メソッドの追加・上書きをした 執事ロボット クラスを定義してみよう。このとき、執事ロボット ファイルは挨拶ロボットファイルと同じフォルダに置く必要がある。

class 執事ロボット extends 挨拶ロボット{//挨拶ロボット クラスを拡張 //属性・プロパティの追加 private String 主人名="ご主人"; //主人名を教えるメソッドの追加 public void set主人(String s){主人名=s;} //挨拶()メソッドの上書き public String 挨拶(){return 主人名+"さま"+super.挨拶();} //スーパークラスの挨拶()メソッドを利用 //デフォルトのコンストラクタ public 執事ロボット(){super();} //主人名 s を教えて生成するコンストラクタ public 執事ロボット(String s){super(); 主人名=s;}

public static void main(String[] args) {

執事ロボット ユキ = new 執事ロボット("田中"); System.out.println(ユキ.挨拶());

} }

実習.直前の実習の続き
4.4.のJava主クラス執事ロボットを、挨拶ロボット クラスを拡張して主人属性を持つクラスとして再定義し、そのオブジェクトユキに、ご主人へ挨拶させる
5.以下の機能(メソッド)を執事ロボットクラスに追加し、yukiに今何時か聞けるようにする。余裕があれば、何時何分何秒か聞けるようにする。

public String 今何時(){ String 返事=主人名+"さま"; int 時=java.util.Calendar.getInstance(). get(java.util.Calendar.HOUR_OF_DAY); if ((3<時)&&(時<12)) 返事+="おはようございます"; else if (時<17) 返事+="こんにちは"; else 返事+="こんばんは"; return 返事+"今"+時+"時です"; }

7.2.メソッドの定義と利用

 前節では、クラスを定義する中でメソッドを定義し、オブジェクトを介してメソッドを利用した。この節ではメソッドの定義や利用の方法の基本を学ぼう。
 一般にメソッドの定義は、
  void set挨拶(String s){ ・・・ } や
  String 挨拶(){ ・・・ }
のように、
  戻り値の型 メソッド名(引数定義の並び){定義の本体}
という形をとる。メソッドを利用する(呼び出す)ときは、
  set挨拶("こんにちは"); や
  挨拶();
のように
  メソッド名(引数(値)の並び);
とする。ここで、引数(値)の並びは、メソッド定義における引数定義の並びと型が順に一致していなければならない。
 特に区別するときは、メソッド内での処理に重点があり戻り値を持たない(型がvoid)メソッドを手続きということもある。一方、void以外の型を持つメソッドを関数といい
  System.out.println(ケン.挨拶());
のように(その戻り値を)式の中で使うことができる。関数は戻り値を持つので、メソッド定義の本体の中で
  return 戻り値;
というreturn文を必ず(引数の値に関わらず)実行する形にしなければならない。さらに、戻り値は当然、メソッド定義の頭部で指定された戻り値の型の値でなければならない。
 ところで、執事ロボット クラスでは2種類の同じ名前のコンストラクタを定義した。
  public 執事ロボット() {…}
  public 執事ロボット(String s) {…}
このように、名前が同じでも引数定義の並びが異なるメソッドは区別される。これをメソッドの多重定義(オーバーロード)という。これを使うと、実質的に同じ意味を持つ(計算・処理を行う)メソッドを、異なる型や個数の引数に対してそれぞれ定義したいとき、それらに同じ名前をつけることができるので便利である。

7.3.staic, private, public

 メソッドは、上に述べたような自分で作成(用意)したメソッドだけでなく、Javaにあらかじめ用意されているメソッドも利用できる。明示的な説明は避けてきたが、これまでもJAVAが用意した様々なメソッドを利用しており、例えば以下のような宣言を持つ。
  1. static void System.out.print(String s)
  2. static double Math.random()
  3. java.util.Scanner(InputStream source)
  4. int nextInt()
 前節のメソッドは(コンストラクタを除いて)オブジェクトを介して実行していたが、1.や2.のメソッドは、オブジェクトを介することなく、直接実行できたことに注意しよう。それを可能にするのが、staticという修飾子である。staticが付いたメソッドはクラスメソッドといい
  クラス名.クラスメソッド
という形で実行できる。また同じクラス内であればクラス名を省略できるので、static修飾子を付けたメソッドは main など他の staticメソッドでそのまま利用できる。なお、3.のようなコンストラクタは特別なクラスメソッドで、static修飾子がなくても
  new コンストラクタ
という形で直接実行できる。
 一方4.のメソッドはstaticではないので、Scannerオブジェクトを生成してからオブジェクトを介してでないと使えない。
 また、メソッド名の前にあるvoidはメソッドが値を返さないことを示し、doubleint等の型名であればそれぞれその型の値を返すことは前節で述べた。
 ここで、これまで説明を省略してきた、private、public の意味について解説しておこう。これらはクラス定義や、クラス定義中の属性やメソッドの前につける修飾子(語)で以下の意味を持つ。
  1. privateはそれを付した属性やメソッドの使用がそのクラスの中だけで有効なことを表し、他のクラスからの使用を禁ずる意味がある。オブジェクトの属性は、private指定をして勝手な使用を禁止する一方で、アクセスのためのpublic指定をしたget属性名()、set属性名() の両メソッドを用意するのが普通である。
  2. publicは他のクラス(ファイル)からの使用を許すことを意味するもので、上の例のように他のクラス(ファイル)から使用したい(させたい)ときは、public指定を付ける。
  3. publicやprivateの修飾子を付けないと、同一ファイル内の他のクラスからの使用を許すことを意味する。
修飾子は他にもあるが、例えばこちらが参考になる。

7.4.Ⓐ引数の受け渡し

 6.3.配列へのキーボード入力で説明したプログラム部分をメソッドAとして独立させると、例えば、以下のようになり、

static int データ入力(double データ[], double 終了値){//メソッドA //実数配列 データ に 終了値 が入力されるまで実数値を読み込む。戻り値はデータ数 java.util.Scanner 標準入力 = new java.util.Scanner(System.in); int データ数=0; for (double 入力値;(入力値=標準入力.nextDouble())!=終了値; データ[データ数++]=入力値); return データ数; }

以下のように、呼び出せる。
public static void main(String[] args) {//メインメソッドA

double 実データ[]=new double[100]; int データ数=データ入力(実データ, -1); for(int i=0; i<データ数; i++) System.out.print(実データ[i]+" ");

}
注.同じクラス内でメソッドを使う場合はクラス名を省略できる。

 同じようでも、データ数 を引数とした次のメソッドBは

static void データ入力(int データ数, double データ[], double 終了値){//メソッドB java.util.Scanner 標準入力 = new java.util.Scanner(System.in); データ数=0; for (double 入力値;(入力値=標準入力.nextDouble())!=終了値; データ[データ数++]=入力値); }


以下のように呼び出してもうまく行かない。何故だろうか。
public static void main(String[] args) {//メインメソッドB

double 実データ[]=new double[100]; int 実データ数=1; データ入力(実データ数,実データ,-1); for(int i=0; i<実データ数; i++) System.out.print(実データ[i]+" ");

}
実習.以下の手順で上の2種類のプログラムの結果を確認せよ
1.入力数を戻り値としたメソッドAを作成し、mainメソッドAで入力値が正しく表示されることを確認する
2.入力数を引数としたメソッドBを作成し、mainメソッドBで入力値を表示させる
3.2.では、渡した引数nに対し、メソッドB内での更新が反映されないことを確認せよ

 入力データ数を引数としたメソッドが正しく働かないのは、Javaでは、呼び出し命令中の変数(実引数)と呼び出されるメソッドの変数(仮引数)とがメモリのまったく別の場所に置かれ、実引数の値が仮引数に渡されて計算が始まる仕組み(値渡し)のためである(データ入力(データ,-1)のように値を渡すことができるのもそのため)。
 すなわち、実引数と仮引数は別の場所にある変数であるから、仮引数に対する更新は実引数に反映されない
データ入力(実データ数,実データ,-1) メソッドB
実引数



仮引数
実データ数1データ数1
実データ実データの場所データデータの場所
-1終了値-1
 それならば、上の実習で、配列仮引数 データ に対する入力が配列実引数 実データ に反映されるのは何故だろうか。それは配列変数の値は配列全体ではなく、配列が配置されている場所(メモリ上のアドレス)だからである。したがって、メソッドB データ入力(int データ数, double データ[], double 終了値) をメインメソッドBで データ入力(実データ数,実データ,-1)と呼び出すと、上表のように仮引数の(初期)値が設定され、メソッドBの計算が始まる。
 配列変数 実データ と データ とは、変数としては異なるがそれらが指しているもの(場所)は同じなので、配列 データ に対する変更が配列 実データ にも反映される。一方、データ入力(実データ数,実データ,-1)に使われているメインメソッドBの変数 実データ とメソッドBの変数 データ数 とは(例え名前が同じでも)異なる変数なので、メソッドBの中で データ数 の値が更新されても、メインメソッドの 実データ数 の値は 1 のままである。
 配列変数だけでなくオブジェクト変数もその値はオブジェクトの場所である。したがって、入力データ数を表す実(仮)引数を配列あるいはオブジェクトとして定義すれば、仮引数に設定した入力データ数が実引数にも反映されるようになる。

//入力データ数を配列要素 データ数[0]で管理 static void データ入力(int データ数[], double データ[], double 終了値){//メソッドC java.util.Scanner 標準入力 = new java.util.Scanner(System.in); データ数[0]=0; for (double 入力値;(入力値=標準入力.nextDouble())!=終了値; データ[データ数[0]++]=入力値); }


//入力データ数をIntオブジェクトで管理 static class 整数{ int 値; }//整数値属性 値 を持つクラス static void getData(整数 データ数, double データ[], double 終了値){//メソッドD java.util.Scanner 標準入力=new java.util.Scanner(System.in); データ数.値 = 0; for (double 入力値;(入力値=標準入力.nextDouble())!=0; データ[データ数.値++]=入力値); }


実習.
適切なメインメソッドを書いて、上のメソッドC、Dが正しく働くことを確認せよ。

課題

本章(7章)の実習で作成した以下のプログラムを作成せよ。 1.7.1節で作成した 挨拶ロボット と 執事ロボット 2.7.4節で作成したメソッドA,B,C,Dとその結果を確認するプログラム

面接授業提出課題2

次のどれかのプログラムを提出せよ。
提出方法:yamasaki.hideki@ouj.ac.jpへのメール内への記述(コピペ)
提出期限:1週間以内
メールタイトル:Javaプログラミング入門提出課題2
メール内容:学生番号、氏名、プログラムの説明(プログラム中に記入してよい)
  1. 入力として何人かの点数を受け取り、それらの偏差値を出力するプログラム
  2. 配列とFOR文を含む適当なプログラム
  3. 執事ロボットクラスに 今何時 メソッドを追加したプログラム