図5.1
(3) 実行ファイルレベルでのプラットフォーム非依存
CやC++では,あるプラットフォーム(計算機など)の基本ソフト(OSなど)上でコンパイルしたプログラムは,その上でしか動作しません.基本ソフトが異なるプラットフォームで実行するためには,またコンパイルしなおしたり,場合によってはソースプログラムを変更する必要があります.
Javaは,コンパイラとインタープリタを併用します.Javaのソースプログラムをコンパイルすると,バイトコードと呼ばれる実行プログラムの中間言語が生成されます.このバイトコードは JVM (Java Virtual Machine) と呼ばれるインタプリタがインストールされているプラットフォーム上であれば,どこでも実行できます.プログラムの実行環境自体を各プラットフォーム上に持たせることで,バイトコードを非常に小さくすることができ,これはネットワーク経由でプログラムをダウンロードして実行するなどの環境に適しています.
インタプリタは,命令を逐次解釈して実行するため速度が遅いという欠点がありますが,Javaではプログラムを高速に実行する仕組みを備えています.
(4) ネットワーク親和性
Javaによって,webブラウザ上で実行する“アプレット”やwebサーバ上で実行する“サーブレット”など,ネットワーク上で実行可能なプログラムを開発できます.もともとJavaはこのようなネットワーク環境での利用が想定されています.JVMは,プログラムの実行状況を厳しく監視するセキュリティ機能が備わっており,疑わしい処理(ローカルファイルへの書き込みなど)が実行されそうな場合,その操作を防ぐことができます.また,前述のように,プログラムサイズが小さいためダウンロードに適していますし,プラットフォーム非依存のためネットワーク上の様々なプラットフォームでプログラムを実行することができます.
Java言語で作成できるプログラムには次のようなものがあります.この講義では,CUIアプリケーションを扱います.
・ CUI (Character User Interface) アプリケーション
コマンドプロンプトやShellなど文字ベースの実行環境 (CUI) で動作する基本的なプログラム.
・ GUI (Graphical User Interface) アプリケーション
ユーザとの情報のやりとりににグラフィックを用い、入出力操作のほとんどをマウスなどのポインティングデバイスによって行なう実行環境 (GUI) で動作するプログラム.
・ Javaアプレット
Webブラウザ上で動作するプログラム.Webサーバからプログラムがダウンロードされ,クライアント側のWebブラウザ上で動作する.
・ Javaサーブレット
Webサーバ上でJavaプログラムが動作し,その結果をWebページとしてクライアントに返す.
・ JSP (Java Server Page)
HTMLにJavaプログラムを埋め込んで,動的なWebページを作成するための仕組み.プログラムはWebサーバ上で実行され,その結果をクライアントに返す.
・ Java Beans
Java言語で作成したプログラムをコンポーネントとして扱うための仕組み.コンポーネントを組み合わせることで,アプリケーションを簡単に作成することが可能.
Eclipseなどの統合開発環境(Integratad Development Environment: IDE)を使う場合は,プログラムを作成・実行するための「プロジェクト」(関連するソースファイルやライブラリなどをまとめて管理して扱う単位)を作成し,IDE上のエディタでソースファイルを作成・編集し,実行します.操作手順は使用するIDEにより異なります.
IDEを使わない場合のプログラム作成・実行手順は,次のようになります.
(1) テキストエディタ(メモ帳,ワードパッド,Meadow,TeraPadなど)を使ってプログラムを記述し,ファイルを".java"という拡張子をつけて保存します.例えば,次のJavaプログラムを作成し,HelloWorld.javaというファイル名で保存します.このとき,class の後に続く名前とファイル名が一致している必要があります.
(プログラム: HelloWorld.java)
public class HelloWorld { public static void main(String[] args) { System.out.print("Hello "); System.out.print("world!\n"); System.out.println("Hello world!"); } }
(2) コマンドプロンプトを実行し,コマンドプロンプト上でソースファイルのあるディレクトリ(フォルダ)に移動します.例えば,C:(ローカルディスク)の中のworkディレクトリの下のprogrammingディレクトリの下にソースファイルHelloWorld.javaを保存した場合は,次のように移動します.
C:\>cd \work\programming
(3) javac コンパイラにソースファイルを読ませ,コンパイルを実 行しバイトコードを作ります.
C:\work\programming>javac HelloWorld.java
(4) コンパイルが正常に終了すると,同じフォルダ内に"HelloWorld.class" というバイトコードが作られます.ファイルはdirコマンドで確認できます.
(5) バイトコードを実行します.Java アプリケーションプログラムを実行するときは,JVMに実行するコードを渡すため,java コマンド + クラスファイル名(拡張子はいりません)と入力します.
C:\work\programming>java HelloWorld
Javaでは,プログラムの単位はクラスなので,必ず
class クラス名 { … }
という記述でプログラムが始まり,{ }の間にこのクラスを定義する変数やメソッ ドを書きます.
ここでは,メソッドの例として,アプリケーションプログラムの実行単位であるmainメソッドを書きますが,プログラム自体はCやC++と同様に{ }で挟まれたブロックの間にメソッドの処理に必要な変数や式を書きます.式の最後にはセミコロン";"を書きます.
クラスやメソッドについては,もう少し後で説明します.
class クラス名 { public static void main(String[] args) { 変数; 式; 式; ・ ・ ・ } }
CやC++と同様に,JAVAプログラムの記述はフリーフォーマットです.従って,プログラムを見やすくするために,コーディングの仕方に注意する必要があります(適切な改行,インデント,コメントの挿入など).
例えば,下の2つのプログラムは同じ動作をするものですが,二つめのプログラムのほうが内容や構造を理解できます.
public class HelloWorld { public static void main(String[] args) {System.out.print("Hello ");System.out.print("world!\n");System.out.println("Hello world!");}}
* 20**/04/01 * 基礎プログラミングおよび演習 * Java サンプルプログラム * 文字列 "Hello World" を表示するクラス * T.Suzuki */ public class HelloWorld { // main メソッド public static void main(String[] args) { // 文字列の表示 System.out.print("Hello "); System.out.print("world!\n"); // \nは改行 // 文字列の表示: printlnは改行付表示 System.out.println("Hello world!"); } // main メソッド } // class HelloWorld
演習5.1 (サンプルプログラム: NamePrintSample.java)
(解答例: NamePrint.java)
次のように画面に表示するプログラムを作成し,コンパイル,実行しなさい.
大学名: 東京電機大学
学部名: 工学部
学科名: 情報通信工学科
氏 名: ○○○○(自分の氏名を入力)
Javaで扱うデータは,型で分類されます.プログラム作成時には,扱うデータに応じて型を指定(宣 言)して使用します.
・ 整数型
byte: 1byte (= 8bit), -128~127
short: 2byte (= 16bit), -32,768~32767
int: 4byte (= 32bit), -2,147,483,648~2,147,483,647
long: 8byte (= 64bit), -9,223,372,036,854,775,808~9,223,372,036,854, 775,807
long型変数に整数を代入する場合は,数値の後に"l"または"L"を付ける.
long l = 1234567890l;
・ 実数型
flort: 4byte (= 32bit), ±3.4E+38~±1.4E-45
float型変数に十数値を代入する場合は,数値の後に"f"または"F"を付ける.
float f = 1.23f
double: 8byte (= 64bit), ±1.8E+308~±4.9E-324
実数型は,数値計算など実数を使用するような計算に用いられます.しかし,有効 桁数は有限のため,誤差に注意する必要があります.
・ 文字型,文字列クラス
char: 2byte (= 16bit)
一文字のみを記憶するデータ型です.プログラム中に文字データを書く場合は,'a' のようにシングルクォーテーションマークを使用します.
String:
文字列を格納するクラスです.プログラム中に文字データを書く場合は,"a"のよう にダブルクォーテーションマークを使用します.
・ 論理型
boolean
論理値trueまたはfalseを記憶するデータ型です.条件式や代入式などの真偽を判断 するときなどに使います.
変数の宣言と代入は,次のように行います.
型 変数名1[, 変数名2,変数名3・・・]; (例) int i = 3; double x, y; char a = 'あ'; String str = "あいうえお"; x = 3.14; y = 2 * x; z = x + y; String text = str + i + "かきくけこ";
変数に数値を代入するには"="を使います.数学のイコール記号とは異なり,Java言語では代入を表し ます.右辺の値が左辺に代入されます.
int a, b; char c1 = 'a'; a = b = 10;
上の2行目では,文字型の変数c1にaという文字を代入しています.
3行目では,整数型の変数a, bに数値を代入していますが,この場合,まずbに10が代入され,次にb の値(=10)がaに代入されます.
型の異なる変数同士の計算や代入には,型変換(キャスト)を行います.キャストを用いないと,期待した演算結果が得られない場合があります.
int a = 10; double b; b = (double)a; // int型のaをdouble型にキャスト
変数名は,扱いたい変数あるいは値の,内容や役割を反映した英語名を付けます.自分のプログラムの見直しが容易になり,他の人からの可読性も高まります.
int serverNumber = 10; double sensorValue; String localServerName = "labServ1";
演習5.2
(1) 摂氏Cを整数値で入力すると,実数値の華氏Fと絶対温度Kに換算し,それらを表示するプログラムを作成しなさい.
ただし,F = 32.0 + 1.8C,K = 273.16 + Cとする.
(サンプルプログラム: TemperatureConversionSample1.java)
(解答例: TemperatureConversion1.java)
(2) 上のプログラムの摂氏温度を,コマンドライン引数で入力するように改良しなさい.
(サンプルプログラム: TemperatureConversionSample2.java)
(解答例: TemperatureConversion2.java)
配列により,同じ型の複数の変数をひとまとめに管理できます.関連した大量のデータを扱うときや,一連のデータを連続的に入出力するときなどは配列を使うと便利です.(参考: Java5以降では,保守性の高いコードを書くために,Collectionを使って配列の使用を減らすことが推奨されますが,ここではC言語やC++言語などに類似した配列表現を扱います.)
配列の宣言は,
データ型[] 配列名; 例)double[] a = new double[5];
のように行います.これは,例えば,double型の大きさの箱を5個用意し,それをaという名前でまとめて扱うという意味です.個々の箱は,それぞれa[0],a[1],・・・,a[4]として扱うことができます.配列数は,必ず 0 から数えます(配列数が5なら,配列は0~4).
次の例は2次元の配列を宣言したものです.
int[][] b = new int[2][3];
3次元の配列の宣言は次のようになります.
int[][][] c = new int[2][2][3];
配列への数値の代入は,次のように行います.
例)サンプルプログラム: ArrayPrintSample.java /* * 2011/06/03 * 2011年度 基礎プログラミングおよび演習 * Java サンプルプログラム (2) * 配列に値を代入し,表示するクラス * T.Suzuki */ class ArrayPrintSample { // main メソッド public static void main(String[] args) { // 配列の宣言 double [] oneDimensionalArray = new double[3]; int [][] twoDimensionalArray = new int[][]{ {1, 2, 3}, {4, 5, 6} }; int [][][] threeDimensionalArray = { { { 7, 8, 9}, {10, 11, 12} }, { {13, 14, 15}, {16, 17, 18} } }; // 配列 oneDimensionalArray に値を代入 oneDimensionalArray[0] = 1.2; oneDimensionalArray[1] = 3.45; oneDimensionalArray[2] = 6.789; // oneDimensionalArray[1]の値を表示 System.out.print("1次元配列\n"); System.out.println("配列の2番目の値 = " + oneDimensionalArray[1] + "\n"); // 配列 twoDimensionalArray の値を表示 System.out.print("2次元配列\n"); for (int i=0; i<2; i++) { for (int j=0; j<3; j++) { System.out.print("[" + i + "][" + j + "] = " + twoDimensionalArray[i][j] + "\n"); } } System.out.print("\n"); // \n は改行 // 配列 threeDimensionalArray の値を表示 System.out.print("3次元配列\n"); for (int i=0; i<2; i++) { for (int j=0; j<2; j++) { for (int k=0; k<3; k++) { System.out.print("[" + i + "][" + j + "][" + k + "] = " + threeDimensionalArray[i][j][k] + "\n"); } } } System.out.print("\n"); // \n は改行 } // main メソッド } // ArrayPrintSample クラス
演習5.3
上のサンプルプログラムをコンパイル,実行しなさい.また,代入値や次元数を変更し,配列の扱いについて理解を深めなさい.
演習5.4 (サンプルプログラム: ArraySortSample.java)(解答例: ArraySort.java, ArraySort2.java)
5つの配列に自然数を入力し,昇順(小さい順)で配列の中身をソートし画面に表示するプログラムを作成せよ.
ヒント: 昇順ソートは次のバブルソートで行えます.
int num = 5; //配列数 int x[num]; //配列 int i, k; int tmp; ・ ・ ・ for (i=num-1; i>=1; i--) { for (k=0; k<i; k++) { if (x[k] > x[k+1]) { tmp = x[k]; x[k] = x[k+1]; x[k+1] = tmp; } } }
ここでは,計算や条件の比較などに使われる演算子をまとめておきます.
演算子 | 使い方 | 意味 |
---|---|---|
= | a = b | bの値をaに代入する |
+ | a = b + c | bとcを足した値をaに代入する |
- | a = b - c | bからcを引いた値をaに代入する |
* | a = b * c | bとcをかけた値をaに代入する |
/ | a = b / c | bをcで割った値をaに代入する |
% | a = b % c | bをcで割った余りをaに代入する |
+= | a += b | aにbを足した値をaに代入する (a = a + b) |
-= | a -= b | aからbを引いた値をaに代入する (a = a - b) |
*= | a *= b | aとbを掛けた値をaに代入する (a = a * b) |
/= | a /= b | aをbで割った値をaに代入する (a = a / b) |
%= | a %= b | aをbで割った余りをaに代入する (a = a % b) |
++ | ++a a++ |
aの値を1増やす.インクリメント演算子. 前置(++a)の場合は先に処理が行われ, 後置(a++)の場合は後で処理が行われる. |
-- | --a a-- |
aの値を1減らす.デクリメント演算子. 前置(--a)の場合は,先に処理が行われ, 後置(a--)の場合は後で処理が行われる. |
演算子 | 使い方 | 意味 |
---|---|---|
== | a == b | aとbは等しい |
< | a < b | aはbより小さい |
> | a > b | aはbより大きい |
<= | a <= b | aはb以下 |
>= | a >= b | aはb以上 |
!= | a != b | aとbは等しくない |
演算子 | 使い方 | 意味 |
---|---|---|
&& | (0 < a) && (a <= 10) | aが0より大きく,かつ,aが10以下 |
|| | (a % 2 == 0) || (a % 3 == 0) | aが2で割りきれる,または,aが3で割り切れる |
! | !(a == 10) | aが10ではない. |
if, switch, while, forの使い方を思い出してください.
if (条件式1) { 条件式1が成立したときに実行される式; } else if (条件式2) { 条件式2が成立したときに実行される式; } else { 条件式1,2が成立しなかったときに実行される式; }
switch (変数または式) { case 定数1: 変数または式が,定数1の場合に実行される式; case 定数2: 変数または式が,定数2の場合に実行される式; ・ ・ ・ default: 上記以外の場合に実行される式; }
while (条件式) { 条件式が成立している間だけ繰り返される式; }
do { 条件式が成立している間だけ繰り返される式; } while (条件式); ←条件式の判定はループの最後
for (初期設定; 反復条件; 変更式) { 制御変数を初期設定から変更式で変更し, 反復条件を満たしている間繰り返される式; }
演習5.5(サンプルプログラム: PrimePrintSample.java)(解答例: PrimePrint.java)
二桁の素数をすべて出力するプログラムを適当な制御構文を用いて作成せよ.
ヒント: (エラトステネスの篩)
(1) 10~99までのすべての値を2, 3, 5, 7のいずれかで割り切れるかを判定する.
判定条件: x % 2 == 0 || x % 3 == 0 || x % 5 == 0 || x % 7 == 0
(2) 割り切れない場合は素数なので,その値を表示する.
演習5.6(サンプルプログラム: PrimeFactrizationSample.java)(解答例: PrimeFactorization.java)
二桁の自然数(10~99)をコマンド引数として入力すると,素因数分解して出力するプログラムを適当な制御構文を用いて作成せよ.
ヒント: 素因数分解プログラムの流れ
(1) 入力値 x が,2, 3, 5, 7のいずれかで割り切れるかを判断.
条件: x % 2 == 0 || x % 3 == 0 || x % 5 == 0 || x % 7 == 0
(2) 割り切れない場合は x は素数.
(3) 割り切れる場合は,
・ まず,xが2より大きく,かつ,2で割り切れる間は文字"2 * "を表示し,xを2で割る.
・ 次に,xが3より大きく,かつ,3で割り切れる間は文字"3 * "を表示し,xを3で割る.
・ 次に,xが5より大きく,かつ,5で割り切れる間は文字"5 * "を表示し,xを5で割る.
・ 次に,xが7より大きく,かつ,7で割り切れる間は文字"7 * "を表示し,x を7で割る.
・ 最後に残った数 x を表示する.
これから,実際にクラスを説明するためにプログラムを作っていきましょう.簡単な例として,次のような足し算を行うクラス Addition と,このクラスを利用して計算するメインメソッドを持つ Calculation クラスを考えていきます.なお,これらはクラスの記述について説明するためのプログラムですので,プログラムの中身についてはあまり気にしないでください.
// リスト 1 // 足し算クラス // ファイル: Addition.java // Addition クラス public class Addition { // (1)フィールドの定義 private int num1; // 同じクラス(Additionクラス)内のみアクセス可 private int num2; // 同じクラス(Additionクラス)内のみアクセス可 public int ans = 0; // どのクラスからもアクセス可 // (2)メソッドの定義 // 変数代入メソッド private void substituteValue(int a, int b) { // (3)同じオブジェクト内のフィールドへの代入 num1 = a; num2 = b; } // 足し算メソッド public int addParameter(int a, int b) { // (4)同じオブジェクト内のメソッドの呼び出し substituteValue(a, b); // (5)同じオブジェクト内のフィールドの参照・代入 ans = num1 + num2; // 戻り値 return ans; } } // Addition クラス
// リスト 2 // 実行クラス // ファイル: Calculation.java // Calculation クラス public class Calculation { // メインメソッド public static void main(String [] args) { // 変数の定義 int a = 5; int b = 10; int result; // (1)オブジェクトの生成 Addition addition = new Addition(); // (2)異なるオブジェクトのフィールドの参照 System.out.println("additionオブジェクトのフィールド ans = " + addition.ans); // (3)異なるオブジェクトのフィールドへの代入 addition.ans = 100; System.out.println("additionオブジェクトのフィールド ans = " + addition.ans); // メソッドの呼び出し // (4)異なるオブジェクトのメソッドの呼び出し result = addition.addParameter(a, b); System.out.println("additionオブジェクトのフィールド ans = " + addition.ans); System.out.println("同じオブジェクトのフィールド result = " + result); // (5)アクセス修飾子の確認 // System.out.println("additionオブジェクトのフィールド ans = " + addition.num1); } // main メソッド } // Calculation クラス
演習5.7
リスト1(Addition.java),リスト2(Calculation.java)を作成し,リスト2のプログラムを実行して動作を確認しなさい.
オブジェクト指向プログラミングは,共通・関連するデータと処理方法をひとまとめにした“プログラムの部品”を作り,その部品を組み合わせることでプログラムを作成します.個々の部品の独立性を高め,部品間の相互依存性をなくすことで,プログラムのメンテナンス性と再利用性を向上させます.この部品のことをクラスといいます.Javaでは,クラスのデータのことをフィールド,処理方法のことをメソッドと呼びます.フィールドやメソッドをまとめてクラスのメンバと言います.
クラス名は,クラスの役割や機能を表す名前を英語名で付けます.単なる番号や内容を想像できないような名前などは使わないでください.また,クラス名は,"JavaSampleClass" のように各単語の先頭を大文字にすることが一般的です.
クラスは,プログラムの部品を作るための設計図であり,それ自体は実体を持っていません.これは,変数の型と変数のようなもので,実際に利用するためにはクラスからオブジェクトを作ります.クラスからオブジェクトを作ることをインスタンス化と言います.
オブジェクトの生成は,リスト2 (1)のようにnew演算子を用いて行います.
クラス名 オブジェクト名 = new コンストラクタ();
コンストラクタについては後で述べますので,ここではクラス名に()をつけたものと考えてください.
publicやprivateは,アクセス修飾子と呼ばれるもので,フィールドやメソッドのアクセス可能範囲を示します.publicとした場合は,すべてのクラスからアクセス可能,つまり,値を参照したり利用したりできます.privateとした場合は,そのメンバが記述されているクラスからのみアクセス可能で,他のクラスからはアクセスできません.
クラス,フィールド,メソッドなどは,アクセス範囲が分かるように,適切な修飾子を使って宣言してください.
フィールドはクラスの中で扱う変数であり,リスト1 (1)のように
変数の型 変数名;
で記述します.これをフィールドの定義といいます.同じオブジェクト内のフィールドは,リスト1 (3)のようにフィールド名をそのまま記述することで利用できます.異なるオブジェクトのフィールドは,リスト2 (2), (3)のように オブジェクト名+ピリオド+フィールド名 で記述します.
前述しましたが,変数名は,扱いたい変数あるいは値の,内容や役割を反映した英語名を付けます.
メソッドは,クラス内のデータの処理方法を与えます.メソッドの定義はリスト1 (2)のように
戻り値の型 メソッド名(引数1,引数2,・・・) { }
とし,{ }で囲まれたブロックの中に処理内容の式を記述します.戻り値がない場合は,戻り値の型をvoidとします.引数がない場合は,メソッド名( ) のように,( )内にはなにも記述しません.
メソッド名は,そのメソッドがどのような処理を行うのかがわかるように,動詞で始まる英語名を付けてください.また,必要ならコメントなども付して何をするメソッドかを明確にしておきます.
同じオブジェクト内のメソッドの呼び出しはリスト1 (4)のように,メソッド名(引数)を記述します.異なるオブジェクトのメソッドの呼び出しはリスト2 (4)のように オブジェクト名+ピリオド+メソッド名(引数) と記述します.
いままで使ってきた main() もメソッドの一つで,プログラムを実行すると最初に呼び出されます.mainメソッドは,1つのクラスにひとつだけ記述でき,次のように書きます.
public static void main(String [] args) { }
mainメソッドの引数はStringクラスの配列になっており,実行時のコマンドライン入力を受け取ります.例えば,リスト3のプログラムを実行するとき,次のように入力することでmainメソッドに引数を渡します.
> java Calculation 20 25 ↑ ↑ args[0] args[1] コマンドライン引数
// リスト3 (リスト2変更) // 実行クラス // ファイル: Calculation.java // Calculation クラス public class Calculation { // メインメソッド public static void main(String [] args) { // 変数の定義 int a = 5; int b = 10; int result; /*** リスト2に追加(ここから) ***/ // コマンドライン引数の処理 if (args.length != 2) { // (1)引数のString配列の要素数が2つではないときの処理 System.out.println("2つの引数を入力してください(デフォルト値は5, 10です)."); } else { // コマンドライン引数が入力されたときの処理 // (2)文字列をint型に変換 a = Integer.parseInt(args[0]); b = Integer.parseInt(args[1]); } /*** リスト2に追加(ここまで) ***/ // オブジェクトの生成 Addition addition = new Addition(); // メソッドの呼び出し result = addition.addParameter(a, b); // 結果の表示 System.out.println("result = " + result); } // メインメソッド } // Calculationクラス
演習5.8
(1) リスト2 下から5行目のコメントアウトマーク(//)を消してコンパイルし,private修飾子のついたメンバには他のクラスからアクセスできないことを確認しなさい.次に,リスト1 9行目の変数(num1)の修飾子をpublicに変更し,リスト1,2ともそれぞれ再コンパイルした後にリスト2のプログラムを実行し,アクセス修飾子の意味を確認しなさい.
(2) リスト3で追加されている変更箇所をCalculation.javaに追加したのちコンパイルし,コマンドライン引数で値を入力して実行しなさい.
演習5.9(解答例: Subtraction.java,Calculation.java)
リスト1のクラスを参考に,2つの整数の引き算を行い,結果を整数で返すメソッド subtractParameter をメンバに持つ引き算クラス Subtraction を作りなさい,また,Substractionクラスから引き算メソッドを呼び出し,結果を表示する命令をリスト3に追加しなさい.
オーバーロードとは,リスト4 (1), (2)のように,同じクラスの中に引数の型や数の異なる同じ名前のメソッドを複数定義することです.リスト5のように,引数の型と数に対応するメソッドが呼び出されます.
// リスト 4 // 四則演算クラス // ファイル: Addition2.java // Addision2クラス public class Addition2 { // フィールドの定義 private int num1; private int num2; public int ans1 = 0; public double ans2 = 0.0; // メソッドの定義 // 変数代入メソッド private void substituteValue(int a, int b) { // 同じオブジェクト内のフィールドへの代入 num1 = a; num2 = b; } // 足し算メソッド(1): 引数は2つのint型 public int addParameter(int a, int b) { // 同じオブジェクト内のメソッドの呼び出し substituteValue(a, b); // 同じオブジェクト内のフィールドの参照・代入 ans1 = num1 + num2; // 戻り値 return ans1; } // 足し算メソッド(2): 名称は(1)と同じで,引数の数が異なる(3つのint型) public int addParameter(int a, int b, int c) { // メソッドのオーバーロード // 戻り値は,引数をすべて足した値 ans1 = a + b + c; return ans1; } // 足し算メソッド(3): 名称は(1)と同じで,引数の型が異なる(2つのdouble型) public double addParameter(double a, double b) { // メソッドのオーバーロード // 戻り値は,引数をすべて足した値 ans2 = a + b; return ans2; } } // Addition2クラス
// リスト 5 // 実行クラス // ファイル: Calculation2.java // Calculation2クラス public class Calculation2 { // mainメソッド public static void main(String [] args) { // 変数の定義 int a = 5; int b = 10; int c = 15; int result1; double f = 1.23; double g = 6.78; double result2; // コマンドライン引数の処理 if (args.length != 2) { // (1)引数のString配列の要素数が2つではないときの処理 System.out.println("2つの引数を入力してください(デフォルト値は5, 10です)."); } else { // コマンドライン引数が入力されたときの処理 // (2)文字列をint型に変換 a = Integer.parseInt(args[0]); b = Integer.parseInt(args[1]); } // オブジェクトの生成 Addition2 addition2 = new Addition2(); // メソッドの呼び出し.引数に対応したメソッド(1)が呼び出される. result1 = addition2.addParameter(a, b); // 結果の表示 System.out.println("足し算メソッド(1): result = " + result1); // メソッドの呼び出し.引数に対応したメソッド(2)が呼び出される. result1 = addition2.addParameter(a, b, c); // 結果の表示 System.out.println("オーバーロードメソッド(2): result = " + result1); // メソッドの呼び出し.引数に対応したメソッド(3)が呼び出される. result2 = addition2.addParameter(f, g); // 結果の表示 System.out.println("オーバーロードメソッド(3): result = " + result2); } // mainメソッド } // Calculation2クラス
演習5.10
リスト4,リスト5をそれぞれコンパイルした後,リスト5のプログラムを実行し,メソッドのオーバーロードについて確認しなさい.
演習5.11(解答例: Subtraction2.java,Calculation2.java)
演習5.9で作成したクラスのメソッド subtractParameter を,2つの実数(double型)の引き算を行い結果を実数で返すようオーバーロードメソッドを追加しなさい.また,リスト5のクラスを参考に,引数の異なる引き算メソッドを呼び出し,結果を表示する命令をリスト5に追加しなさい.
コンストラクタは,オブジェクトを生成するときに呼び出される特殊なメソッドで,下のリスト6 (1)のようにクラスと同じ名前で戻り値がありません.コンストラクタは,主にオブジェクトの初期化などに使われます.また,リスト6 (2)のようにオーバーロードできます.
前述のリストのように,クラスの中にコンストラクタを記述しなくても,引数なしのコンストラクタが自動的に用意されます.これをデフォルトコンストラクタと言います.
// リスト 6 // 四則演算クラス // ファイル: Addition3.java // Addition3クラス public class Addition3 { // フィールドの定義 private int num1; private int num2; public int ans1; public double ans2; // (1)コンストラクタの定義 Addition3() { // クラス名と同じ名前のメソッド // クラス内のフィールドの初期値の設定 num1 = 0; num2 = 0; ans1 = 0; ans2 = 0.0; } // (2)コンストラクタのオーバーロード(引数が異なる) Addition3(int a, int b) { // クラス内のフィールドの初期値の設定 num1 = a; num2 = b; ans1 = 0; ans2 = 0.0; } // メソッドの定義 // 足し算メソッド(1): 引数なし.コンストラクタで初期化された値を使う. int addParameter() { // 同じオブジェクト内のフィールドの参照・代入 ans1 = num1 + num2; // 戻り値 return ans1; } // 足し算メソッド(2): 名称は(1)と同じで,引数の数が異なる(2つのint型) int addParameter(int a, int b) { // メソッドのオーバーロード // 戻り値は,引数をすべて足した値 ans1 = a + b; return ans1; } // 足し算メソッド(3): 名称は(1)と同じで,引数の数が異なる(3つのint型) int addParameter(int a, int b, int c) { // メソッドのオーバーロード // 戻り値は,引数をすべて足した値 ans1 = a + b + c; return ans1; } // 足し算メソッド(4): 名称は(1)と同じで,引数の型が異なる(2つのdouble型) double addParameter(double a, double b) { // メソッドのオーバーロード // 戻り値は,引数をすべて足した値 ans2 = a + b; return ans2; } } // Addition3クラス
// リスト 7 // 実行クラス // ファイル: Calculation3.java // Calculation3クラス public class Calculation3 { // mainメソッド public static void main(String [] args) { // 変数の定義 int a = 5; int b = 10; int c = 15; int result1; double f = 1.23; double g = 6.78; double result2; // コマンドライン引数の処理 if (args.length != 2) { // (1)引数のString配列の要素数が2つではないときの処理 System.out.println("2つの引数を入力してください(デフォルト値は5, 10です)."); } else { // コマンドライン引数が入力されたときの処理 // (2)文字列をint型に変換 a = Integer.parseInt(args[0]); b = Integer.parseInt(args[1]); } // (1)コンストラクタの呼び出しによるオブジェクトの生成 Addition3 addition3 = new Addition3(); // メソッドの呼び出し result1 = addition3.addParameter(); System.out.println("足し算メソッド(1)(値はコンストラクタで設定): result = " + result1); result1 = addition3.addParameter(a, b); System.out.println("足し算メソッド(1)(値はコマンドライン引数で設定): result = " + result1); } // mainメソッド } // Calculation3クラス
演習5.12
(1)リスト6,7をそれぞれコンパイルし,リスト7のプログラムを実行して,コンストラクタの動作を確かめなさい.
(2)リスト7において,addition3オブジェクトを作るコンストラクタを,
Addition3 addition3 = new Addition3(a, b);
に変更した後コンパイルし,プログラムを実行して動作の違いを確かめなさい.
演習5.13(解答例: Subtraction3.java,Calculation3.java)
リスト6を参考に,Addition3クラスと同様の形でSubtractionクラスのコンストラクタを追加しなさい.また,リスト7にSubstractionオブジェクトを生成し,メソッドを呼び出す命令を追加して実行しなさい.
オブジェクト指向プログラミングの大きな特徴のひとつとして,継承があります.継承とは,あるクラスのメンバを別のクラスで受け継いで利用するための仕組みで,元のクラスをスーパークラス(あるいは親クラス),受け継いだクラスをサブクラス(あるいは子クラス)といいます.サブクラスでは,スーパークラスのメンバを定義なしに使え,また,サブクラスで定義したメンバは当然使えます.ただし,スーパークラスのプライベート変数は,サブクラスでは使えません.
また,リスト8 (4)のように,スーパークラスのメソッドをサブクラスで定義しなおすこともできます.これをメソッドのオーバーライドと言います.ただし,メソッドのオーバーロードと異なり,メソッドの引数と戻り値は同じでなければなりません.
クラスを継承してサブクラスを作成するには,次のようにextendsを使います.
// リスト 8 // 掛け算クラス // ファイル: Multiplication.java // (1)Addition3クラスを継承したMultiplicationクラス public class Multiplication extends Addition3 { // フィールドの定義 public int ans; //コンストラクタの定義 Multiplication() { ans = 0; } // (2)新たなメソッドの定義 public int multiplyParameter(int a, int b) { // a×bの計算 for (int i=0; i<b; i++) { // (3)スーパークラスのメソッドは,そのまま呼び出せる. ans = addParameter(ans, a); } return ans; } // (4)メソッドのオーバーライド.引数と戻り値はスーパークラスと同じ. int addParameter(int a, int b, int c) { // メソッドの内容を変更 System.out.println("メソッドがオーバーライドされました"); return a + b + c; } } // Multiplicationクラス
// リスト 9 // 実行クラス // ファイル: Calculation4.java // Calculation4クラス public class Calculation4 { // mainメソッド public static void main(String [] args) { // 変数の定義 int a = 5; int b = 10; int c = 15; int result1; double f = 1.23; double g = 6.78; double result2; // コマンドライン引数の処理 if (args.length != 2) { // (1)引数のString配列の要素数が2つではないときの処理 System.out.println("2つの引数を入力してください(デフォルト値は5, 10です)."); } else { // コマンドライン引数が入力されたときの処理 // (2)文字列をint型に変換 a = Integer.parseInt(args[0]); b = Integer.parseInt(args[1]); } // オブジェクトの生成 Multiplication multiplication = new Multiplication(); // (1)スーパークラスの足し算メソッドの呼び出し result1 = multiplication.addParameter(a, b); System.out.println("スーパークラスの足し算メソッド: result = " + result1); // (2)サブクラスで定義した掛け算メソッドの呼び出し result1 = multiplication.multiplyParameter(a, b); System.out.println("サブクラスの掛け算メソッド: result = " + result1); // (3)オーバーライドメソッドの呼び出し result1 = multiplication.addParameter(a, b, c); System.out.println("サブクラスで定義したオーバーライドメソッド: result = " + result1); } // mainメソッド } // Calculation4クラス
演習5.14
リスト8,9をそれぞれコンパイルし,リスト9のプログラムを実行して,クラスの継承によるメソッドの動作を確かめなさい.
演習5.15(解答例: Division.java,Calculation4.java)
リスト8,9を参考に,Subtractionクラスを継承して割り算を行うサブクラスDivisionを作りなさい.また,スーパークラスであるSubtractionクラスのsubtractメソッドを使って,2つの整数の割り算を行い結果を整数で返すメソッドdivideを作りなさい.リスト9のクラスに,Divisionクラスのメソッドを呼び出す命令を追加し,動作を確かめなさい.
演習5.16(解答例: PersonInfo.java,PersonInfoViewer.java)
次の条件を満たす2つのクラスを作成し,動作を確認しなさい.
【PersonInfoクラス】
<フィールドの定義>
・名を代入するStringクラスのprivate変数.
・姓を代入するStringクラスのprivate変数.
・誕生年を代入するint型のprivate変数.
・誕生月を代入するint型のprivate変数.
・誕生日を代入するint型のprivate変数.
・年齢を代入するint型のprivate変数.
・所属を代入するStringクラスのprivate変数.
<コンストラクタの定義>
・引数のないデフォルトコンストラクタとして,フィールドの各変数に自分の情報を代入するコンストラクタを作る.
ただし,ageについては,次のカレンダークラスを用いて,誕生年との差を代入すること.
import java.util.GregorianCalendar; import static java.util.GregorianCalendar.*; class クラス名 () { // フィールドの定義 // カレンダーオブジェクトの生成 GregorianCalendar today = new GregorianCalendar(); コンストラクタ() { 代入式; ・・・ 年齢 = today.get(YEAR) - 誕生年; ・・・ } コンストラクタ(引数) { 代入式; ・・・ } // メソッドの定義 }
・各フィールドに入力する値を引数としてオーバーロードしたコンストラクタを作る.
<メソッド>
フィールドの情報を表示する.
【PersonInfoViewerクラス】
<mainメソッド>
PersonInfoクラスのメソッドを用いて,情報を表示する.
演習5.17(解答例: MyInfo.java,MyInfoViewer.java)
次の条件を満たすクラスを作成し,動作を確認しなさい.
【MyInfoクラス】
<継承>
PersonInfoクラスを継承する.
<フィールド>
・自分の好みや趣味などを代入するStringクラスのプライベート変数を定義.
<メソッド>
・スーパークラスの情報に加えて,サブクラスで追加した情報を表示する.
<MyInfoViewerクラス>
・MyInfoクラスのメソッドを用いて,情報を表示する.