今回は複素数の計算を行うプログラムを題材として、オブジェクト指向プログラミングについて学びます。
ふたつの複素数の加算を行うメソッドを作ってくださいと現段階で言われたとすると、 あなたは以下のようなソースを書こうとして困ると思います。
static double add(double re1, double im1, double re2, double im2){
double re, im;
re = re1 + re2;
im = im1 + im2;
return re; // 困った。double の値をひとつしか返せない。
}
複素数はそれ自身ひとつの数であるのに、 プログラムではふたつの double を使わないと表せません。 つまり、 double 型変数をふたつもった一塊の型が新しく必要になります。 オブジェクト指向プログラミングでは、 複数のデータとそれを扱うメソッドを一塊にした型を作ります。
(C 言語を既習の人向け) C 言語では、そういうときは構造体を使うとうまくいきました。 構造体に自分のデータを扱う関数をまとめたものがオブジェクトです。
例えば、複素数を表す型は以下に挙げる性質を持ちます。
このようにそのものに一般的な性質を記述したものを クラス といい、 その性質をもった個々のものを オブジェクト といいます。 あるクラスに属す変数やメソッドをそのクラスの メンバ といいます。 クラスの定義の仕方は以下のようになります。
class クラス名{
// メンバ変数とメンバメソッドを定義する
}
例えば、複素数のクラスは以下のように記述できます。
class complex{
double re, im; // メンバ変数
public static add(complex a, complex b){
// 中身は略
}
// 他のメソッド
}
複素数クラスから複素数のオブジェクトを作るには、以下のようにします。
complex a = new complex();
01 public class complex{
02 private double re,im; // メンバ変数
03
04 public complex(double x, double y){ // コンストラクタ
05 re = x;
06 im = y;
07 }
08
09 public static complex plus(complex x , complex y){
10 return new complex(x.re + y.re, x.im + y.im);
11 }
12
13 public static complex multiply(complex x , complex y){
14 return new complex(x.re*y.re - x.im*y.im, x.re*y.im + x.im*y.re);
15 }
16
17 public String toString(){ // a + bi という表記に整えるメソッド
18 String s = "";
19 if(re != 0)
20 s += re;
21 if(im >0)
22 s += "+" + im + "i";
23 else if(im < 0)
24 s += im + "i";
25 return s;
26 }
27 }
class sample5a{
public static void main(String[] args){
complex a,b,c;
a = new complex(1.0,1.0);
b = new complex(-1.0,1.0);
c = complex.plus(a,b);
System.out.println(a.toString() + " + " + b.toString() + " = " + c.toString());
c = complex.multiply(a,b);
System.out.println(a.toString() + " * " + b.toString() + " = " + c.toString());
}
}
g1*****@ux001>javac complex.java g1*****@ux001>javac sample5a.java g1*****@ux001>java sample5a 1.0 + 1.0i + -1.0 + 1.0i = 2.0i 1.0 + 1.0i * -1.0 + 1.0i = 2.0
今回は、 sample5a が以下のように (なんとなく) わかれば結構です。
複素数というクラスを作ることによって、 それを使うときには加算や乗算の中身などを気にしなくてよくなりました。 オブジェクト指向プログラミングをうまく使うと、 このようにプログラムの部品を作ることができます。
static を前につけると、 static なメンバが定義できます (例: 9 行目の add)。
static なメンバ はクラスごとにあるメンバで、 static ではないメンバはオブジェクトごとにあります。 以下に図解します。
// re, im はオブジェクト a, b, c それぞれにある (static ではない) // add, multiply はクラス complex にひとつだけ (static) complex (add, multiply) -+- a (re, im) | +- b (re, im) | +- c (re, im)
参照 はオブジェクトの名前です。
コンストラクタを呼び出すと参照が戻り値として得られます。
あるオブジェクトのメンバを用いるときは、ドット演算子 . を使って、
参照.メンバ とします。
static なメンバを用いるときも同様にドット演算子 . を使って、
クラス名.メンバ とします。
参照を入れる変数を作るときは、 クラス名 変数名; とします。
参照を引数とするメソッドを定義するときも同様です。
オブジェクト指向プログラミングについて概観しました。 余力のある人は練習として、複素数の他の演算を定義してください。