第9章 クラスライブラリについて
9.4 クラス型の変数をメソッドで利用する
これまでの学習でクラス型も参照データ型であることは理解できたと思います。型の1つであるならメソッドの引数や戻り値の型として当然利用できます。利用方法は基本データ型と同じように、型として宣言すればよいので特に難しくはありません。
次の項でクラス型の変数を利用したプログラムを紹介していきます。
9.4.1 クラス型変数をメソッドの引数として利用するプログラム
引数にクラス型を定義しているメソッドを呼び出して、その引数(オブジェクト)を受け取り、そのオブジェクトのインスタンスメンバの使い方を確認します。クラス変数を引数とするメソッドの使い方について学習しましょう。
① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch09
③ 名前: Computer2
ソースコード① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch09
③ 名前: ObjectAsArgument
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる
Computer2.java
package jp.co.f1.basic.ch09; public class Computer2 { private String os; private int memory; // コンストラクタ public Computer2() { this.os = ""; this.memory = 0; System.out.println("パソコンを作成しました。"); } /* * アクセサメソッド */ public String getOs() { return os; } public int getMemory() { return memory; } public void setOs(String os) { this.os = os; } public void setMemory(int memory) { this.memory = memory; } public void show() { System.out.println("パソコンのOSは「" + this.os + "」です。"); System.out.println("メモリサイズは「" + this.memory + "MByte」です。"); } }
ObjectAsArgument.java
package jp.co.f1.basic.ch09; public class ObjectAsArgument { /* * 引数にクラス型変数のComputer2オブジェクト情報を受け取り、OSの適正メモリサイズチェックを行います。 */ public static void checkMemory(Computer2 com) { int reasonableMemory; //適正メモリ値格納変数 String os = com.getOs(); //引数のクラス型変数からOS名を取得 int memory = com.getMemory(); //引数のクラス型変数からメモリサイズを取得 com.show(); //PC情報表示 //OS名から適正メモリサイズを判定 if (os.equals("Windows7")) { //OSがWindows7の場合 reasonableMemory = 3072; } else if (os.equals("WindowsVista")) { //OSがWindowsVistaの場合 reasonableMemory = 2048; } else { //その他のOSの場合 reasonableMemory = 1024; } //適正メモリサイズチェック if (memory >= reasonableMemory) { System.out.println("⇒メモリサイズは適正です。"); } else { System.out.println("⇒メモリの増設をお勧めします。"); } System.out.println("------------------------------------"); } public static void main(String[] args) { //Computer2クラスをオブジェクト化 Computer2 com1 = new Computer2(); Computer2 com2 = new Computer2(); //PC情報を設定 com1.setOs("Windows7"); com1.setMemory(2048); com2.setOs("WindowsVista"); com2.setMemory(2048); //引数にクラス型変数(オブジェクト)を与えてメソッド呼び出し System.out.println("------------------------------------"); checkMemory(com1); checkMemory(com2); } }実行結果
解説
mainメソッドの処理側ではこれまで学習してきたように、35、36行目でComputer2オブジェクトを2つ生成しています。
そして39~42行目では35、36行目で生成したオブジェクトの、インスタンスメソッドであるアクセサメソッド(set~)を利用して各PC情報の設定を行っています。
//Computer2クラスをオブジェクト化 Computer2 com1 = new Computer2(); Computer2 com2 = new Computer2(); //PC情報を設定 com1.setOs("Windows7"); com1.setMemory(2048); com2.setOs("WindowsVista"); com2.setMemory(2048);
図 9.4.1: オブジェクト2つ作成
46、47行目でクラス型変数(com1、com2)を引数にcheckMemoryメソッドを呼び出してメモリのチェックをOS毎に行っています。
//引数にクラス型変数(オブジェクト)を与えてメソッド呼び出し System.out.println("------------------------------------"); checkMemory(com1); checkMemory(com2);
9.4.2: クラス型変数の引数と仮引数の関係
続いてcheckMemoryメソッドが呼び出された処理の説明を行います。
図9.4.1で説明したように7行目の仮引数のcomに引数情報であるcom1の値(オブジェクトの場所情報)が代入されます。この情報を元にcheckMemoryメソッド内で処理が動作することになります。
public static void checkMemory(Computer2 com){
checkMemoryメソッド内では呼び出し元からの情報が代入されているcomを利用して情報を取得します。
9、10行目ではインスタンスメソッドである、アクセサメソッド(getXXX)を利用して各PC情報の取得し変数に代入しています。
11行目ではshowメソッドを利用してPC情報を画面に出力しています。
実行結果からも確認できるようにmain側で設定した値と同じ情報が出力され、クラス型変数をメソッドの引数に利用しても正しく情報の表示ができています。
13~23行目でOSに対応した適性のメモリサイズを判定し変数に代入しています。com1のOSは「Windows7」となっているので、16行目の処理に該当し適正メモリサイズとして「3072」が変数に設定されます。
//OS名から適正メモリサイズを判定 if(os.equals("Windows7")){ //OSがWindows7の場合 reasonableMemory = 3072; }else if(os.equals("WindowsVista")){ //OSがWindowsVistaの場合 reasonableMemory = 2048; }else{ //その他のOSの場合 reasonableMemory = 1024; }
26~30行目の処理で求めた適正メモリ値の変数と、実際にパソコンオブジェクトに設定されているメモリ値のチェックを行います。設定されているメモリ値が適正メモリ値以上なら、画面に「⇒メモリサイズは適正です。」と表示され、そうでなければ「⇒メモリの増設をお勧めします。」と表示を行います。
//適正メモリサイズチェック if(memory >= reasonableMemory){ System.out.println("⇒メモリサイズは適正です。"); }else{ System.out.println("⇒メモリの増設をお勧めします。"); } System.out.println("------------------------------------");
実行結果からも確認できるように、実際に設定されているメモリ値は「2048」、適正値は「3072」のため画面に「⇒メモリの増設をお勧めします。」と、判定された結果が正しく表示されています。
47行目でもう1度checkMemoryメソッドが呼び出されています。46行目と違う点は、引数に設定した情報がcom1からcom2になっている点です。結果としてcheckMemoryメソッド内で参照する情報がcom1からcom2の指すオブジェクトに変わるだけで、内部の処理としてcom1と同じようにOSに適したメモリサイズを判定し、メモリサイズが適正なのかを判断する動作を行います。
実行結果からも分かるようにcom2はmainメソッド内でOS「WindowsVista」、メモリ「2048」が設定されているため、出力結果として「⇒メモリサイズは適正です。」と画面に出力されます。
9.4.2 クラス型変数をメソッドの戻り値として利用するプログラム
戻り値にクラス型を定義しているメソッドを呼び出して、その戻り値情報を表示するプログラムです。クラス変数を戻り値とするメソッドの使い方について学習しましょう。
① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch09
③ 名前: Computer3
ソースコード① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch09
③ 名前: ObjectAsReturnValue
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる
Computer3.java
package jp.co.f1.basic.ch09; public class Computer3 { private String os; private int memory; // コンストラクタ public Computer3() { this.os = ""; this.memory = 0; } // コンストラクタ(引数あり) public Computer3(String os, int memory) { this.os = os; this.memory = memory; } /* * アクセサメソッド */ public String getOs() { return os; } public int getMemory() { return memory; } public void setOs(String os) { this.os = os; } public void setMemory(int memory) { this.memory = memory; } public void show() { System.out.println("パソコンのOSは「" + this.os + "」です。"); System.out.println("メモリサイズは「" + this.memory + "MByte」です。"); } }
ObjectAsReturnValue.java
package jp.co.f1.basic.ch09; public class ObjectAsReturnValue { /* * 引数のOS名から適正なメモリを判定し、その情報を元に * コンピュータオブジェクトを生成して返します。 */ public static Computer3 makeComputer(String os) { // 適正メモリ値格納変数 int reasonableMemory; // OS名から適正メモリサイズを判定 if (os.equals("Windows7")) { // OSがWindows7の場合 reasonableMemory = 3072; } else if (os.equals("WindowsVista")) { // OSがWindowsVistaの場合 reasonableMemory = 2048; } else { // その他のOSの場合 reasonableMemory = 1024; } // 引数ありのコンストラクタでオブジェクトを生成 Computer3 com = new Computer3(os, reasonableMemory); // 戻り値にcomを設定 return com; } public static void main(String[] args) { // メソッドの引数に設定する変数を宣言 String os1 = "Windows7"; String os2 = "WindowsXP"; // OS名を引数に設定してメソッドを呼び出す。 Computer3 com1 = makeComputer(os1); Computer3 com2 = makeComputer(os2); // 各メソッドの戻り値からオブジェクト情報を表示する System.out.print("作成した1台目の"); com1.show(); System.out.println("------------------------------------------------"); System.out.print("作成した2台目の"); com2.show(); } }実行結果
解説
mainメソッドの処理側では33、34行目でメソッドの引数に渡すOS名の変数を宣言しています。
//メソッドの引数に設定する変数を宣言 String os1 = "Windows7"; String os2 = "WindowsXP";
37、38行目で先程宣言したOS名が格納されている変数を引数に、makeComputerメソッドを呼び出して戻り値としてオブジェクトを受け取ります。今回は戻り値がクラス型の為、代入する変数をComputer3でクラス型変数を宣言しています。
//OS名を引数に設定してメソッドを呼び出す。 Computer3 com1 = makeComputer(os1); Computer3 com2 = makeComputer(os2);
37行目のmakeComputerメソッド呼び出しを例に説明を行います。
まずmainメソッド側で設定した引数情報が、7行目の仮引数の変数osに代入されます。(※String型もクラスなのでオブジェクトの参照情報がコピーされます)この引数情報を元にmakeComputerメソッドの処理が動作して行きます。
public static Computer3 makeComputer(String os){
12~22行目の処理は9.4.1のサンプルでも目にした処理を再利用して、OSに対して適正なメモリサイズの判定を行っています。今回の例では引数情報のOS名は「Windows7」なので、15行目の処理で適正のメモリサイズは3072が変数reasonableMemoryに設定されます。
//OS名から適正メモリサイズを判定 if(os.equals("Windows7")){ //OSがWindows7の場合 reasonableMemory = 3072; }else if(os.equals("WindowsVista")){ //OSがWindowsVistaの場合 reasonableMemory = 2048; }else{ //その他のOSの場合 reasonableMemory = 1024; }
25行目の処理で引数情報のOS名と先程の処理で判定されたメモリサイズを元に、引数ありのコンストラクタを呼び出してオブジェクトの生成を行っています。その結果、このオブジェクトはOS「Windows7」、メモリ「3072」が設定されます。
//引数ありのコンストラクタでオブジェクトを生成 Computer3 com = new Computer3(os, reasonableMemory);
28行目で25行目の処理で生成したオブジェクトを戻り値として返しています。
//戻り値にcomを設定 return com;
main側に処理が戻り37行目のcom1には、makeComputerメソッドの戻り値であるcomの値が代入されます。
38行目の処理も同様です。但し同じメソッドを呼び出していても、makeComputerメソッド内でComputer3オブジェクトを毎回作成しているので、com1とcom2は別のオブジェクトを指していることになります。
Computer3 com1 = makeComputer(os1); Computer3 com2 = makeComputer(os2);
図 9.4.3: クラス型変数の戻り値の関係
com1とcom2のインスタンスメソッドであるshowメソッドを利用して、画面に設定されているPC情報を表示しています。
//各メソッドの戻り値からオブジェクト情報を表示する System.out.print("作成した1台目の"); com1.show(); System.out.println("------------------------------------------------"); System.out.print("作成した2台目の"); com2.show();
実行結果からも分かるようにcom1はOS「Windows7」に適したメモリ「3072」が設定され、com2はOS「WindowsXP」に適したメモリ「1024」が設定されているので、makeComputerメソッド内で正しく判定されていることが確認できます。
今回紹介した2つのサンプル以外にも、引数も戻り値もクラス型でメソッドを作成することが可能です。
クラスも型になるのでメソッドの引数や戻り値に利用できることを覚えましょう。
ポイント
- クラスも基本データ型のように、メソッドの引数や戻り値に利用することができる。
9.4.3 値渡しと参照渡しについて
これまでの項でクラス型変数同士の代入は「オブジェクトの場所情報」のコピーが行われることや、メソッドの引数にクラスも扱えることを学習してきました。メソッドの引数にクラス型と基本データ型を使った場合の違いに気をつける必要があります。基本データ型の受け渡しを値渡し、クラス型の変数の受け渡しを参照渡しと呼びます。
-
参照渡しの特徴:
オブジェクトの場所情報が引数と仮引数の間でコピーされる。どちらも同じオブジェクトを指し示しており呼び出し先で変更を行うと、呼び出し元に処理が戻って来た時には変更された状態になっている。
-
値渡しの特徴:
値が引数と仮引数の間でコピーされる。値は同じものになるが呼び出し先で変数の値を書き換えて、呼び出し元に処理が戻ってきた場合引数に利用した変数に影響はない。
図 9.4.4: 参照渡し
図9.4.3で示したcheckMemoryメソッドのように、クラス型の変数を引数としたときには、呼び出し元(mainメソッド)の変数com1が指すオブジェクトと、呼び出し先(checkMemoryメソッド)の変数comが指すオブジェクトは同一のものになります。
この節の最初に説明したように、クラス型の変数に代入が行われると、代入された変数は代入した変数と同じオブジェクトを指すようになります。この仕組みはメソッドの引数と仮引数の代入にも当てはまります。
オブジェクトがコピーされて2つに増える訳ではありません。
同じオブジェクトを参照しているということで、呼び出し先で値の変更を行ってしまうと、呼び出し元で値の参照を行った時にはデータが書き換わっているのでクラス型変数をメソッドの引数にする場合は注意が必要です。
図 9.4.5:値渡し
図9.4.4で示したsetMemoryメソッドのように基本データ型の変数を引数にした場合は、その呼び出し元(mainメソッド)の変数memoryと、呼び出し先(setMemoryメソッド)の変数mの値は同じですが、クラス型変数の参照渡しと違い別々の変数になります。メソッドの引数と仮引数の間では値のみのコピーが行われるだけです。これにより呼び出し先で変数の値を書き換えても、呼び出し元の変数に影響が出ることはありません。
基本データ型、クラス型をメソッドの引数に利用しても、結局どちらも変数の中身をコピーしていることに変わりはありません。その変数の中身がオブジェクトの場所情報なのか、実データ(数値、文字など)なのかの違いで呼び方が変わります。
メソッドの引数の渡し方には「値渡し」と「参照渡し」の2種類のみしかないので、この違いを正しく理解しておくことが重要になります。
ポイント
- メソッドの引数にクラス型変数を設定すると参照渡しになり、基本データ型を設定すると値渡しになる。