自作クラスの設計

ファイルはzipフォルダに納められています。
解凍ソフト(Aladdin Expander等)を使って解凍して下さい。

2つの座標を組に

フィールドの設計

クラスを設計する時1番大切なのは、どんなデータをグローバル変数(フィールド)にするかと言う事です。
此処では、2点を表す4つのデータを1パックにしたクラスにしますので、フィールドは以下の4つになります。

int x1; //点1のx座標
int y1; //点1のy座標
int x2; //点2のx座標
int y2; //点2のy座標

コンストラクタの設計

コンストラクタには、インスタンス化されたフィールドに初期値として何を設定するのか、を記述します。
ですから、コンストラクタには、設定したい初期値を受け取る為の仮引数を設けます。
初期値は、色々なパターンで指定出来ると便利ですから、幾つものコンストラクタがオーバーロードされる事が多々有ります。
此処でも、以下の3種類のコンストラクタを定義しておく事にしましょう。

@引数無し

初期値の指定が無い時は、点1、点2の双方の座標を「(0, 0)」とする事にします。

TwoPoints()

A4つのint型引数

4つのデータを「x1」「y1」「x2」「y2」の順で受け取ります。

TwoPoints(int x1, int y1, int x2, int y2)

此処では、仮引数名をフィールドの変数名と同名にしています。
此は、此のコンストラクタを利用するユーザに対し、「此の仮引数で受け取った値を此のフィールドに設定する」事ははっきり解る様にする為ですが、コンストラクタ内部にはスコープの異なる同名の変数が存在する事になります。
其処で此を区別する為に、フィールドの変数名には「this.」を付け、以下の様に書きます。

this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;

B2つのPointクラスの引数

1点のx座標とy座標とをパックにしたクラス「Point」を使い、2つの点の初期値を受け取ります。
此の様にコンストラクタの引数には、型だけでなくクラスも指定出来ます。

TwoPoints(Point p1, Point p2)

自作クラスの利用

自作クラス「TwoPoints」を使って、今迄配列の中にバラバラに入っていた4つのデータをまとめて扱える様にします。
コンストラクタを呼び出して初期値を設定します。

例: TwoPoints data = new TwoPoints(20, 110, 120, 110);

此処では、此等のデータが沢山有りますので、オブジェクト配列にします。

TwoPoints[] data = new TwoPoints[10]; //要素数10個

コーディングとコンパイル

Javaでは原則として、1つのファイルに1つのクラスを記述します。
此処では、プログラムの中心となる「HouseCA2.java」の他に、自作クラス「TwoPoints」を作ります。
此は即ち、「TwoPoints.java」と言うソースファイルを作成する事です。
HouseCA2.java」ではTwoPointsクラスを利用しているので、先に「TwoPoints.java」をコンパイルし、「TwoPoints.class」を作成しておかなければなりません。

メソッドの設計

メソッドの作成は、ユーザ定義メソッドと全く同じです。
仮引数に値を受け取る事も、メソッドを実行した結果を呼び出し側にも返せます。
又、メソッド内に宣言したローカルな変数も使えます。

@セッタメソッド

1つのフィールドにデータを設定するメソッドをセッタメソッドと言います。
セッタメソッドは、以下の様な命令規則が有ります。

public void setXXX(仮引数)

此処では、以下のセッタメソッドを用意します。

void setX1(int x)
void setY1(int y)
void setX2(int x)
void setY2(int y)

此等のメソッドを呼び出す時は、ターゲットとなるインスタンス化されたオブジェクトを指定し、実引数に具体的な座標値を指定します。

例: TwoPoints data = new TwoPoints(10, 10, 40, 40);
data.setX1(20);

Aゲッタメソッド

フィールドに設定されているデータを取り出すメソッドをゲッタメソッドと言います。
ゲッタメソッドは、以下の様な命令規則が有ります。

public フィールドの型 getXXX()

此処では、以下のゲッタメソッドを用意します。

int getX1()
int getY1()
int getX2()
int getY2()

此等のメソッドを呼び出す時は、ターゲットとなるインスタンス化されたオブジェクトを指定し、戻り値を受け取る変数を用意するか、又は式中にメソッドを書きます。

例: TwoPoints data = new TwoPoints(10, 10, 40, 40);
int x1 = data.setX1();

B操作メソッド

此のクラスを使った場合、どんなメソッドを用意しておけば便利でしょうか?
此処では、ターゲットとなるオブジェクトのデータを使って直線を描くメソッドを作ってみましょう。
画面情報であるGraphicsクラスのオブジェクトは、仮引数で受け取ります。
又、「x座標」「y座標」それぞれの指定分だけ平行移動させるメソッドも作る事にします。

public void drawLine(Graphics g)
public void drawLine(int dx, int dy, Graphics g)

此等のメソッドを呼び出す時は、ターゲットとなるインスタンス化されたオブジェクトを指定し、引数としてGraphicsクラスのオブジェクトと平行移動するメソッドでは移動分の座標値を渡します。

例: TwoPoints data = new TwoPoints(10, 10, 40, 40);
data.drawLine(g);
data.drawLine(50, 0, g);
ソース ダウンロード
HouseCA.java TwoPoints01.zip
HouseCA2.java

2つの点を扱うクラス

フィールドの設計

今度のTwoPoints2クラスでは、「2つの点を扱うクラス」と考えて、2つのPointクラスのオブジェクト「p1」と「p2」をフィールドのクラス変数にする事にしましょう。

Point p1; //点1のx, y座標
Point p2; //点2のx, y座標

Pointクラスのオブジェクト「p1」と「p2」は宣言されただけで、未だインスタンス化されていません。

コンストラクタの設計

@引数無し

引数が無い時は、2点の座標を共に「(0, 0)」とする事にします。

Pointクラスのコンストラクタを用いてインスタンス化します。

TwoPoints2()
p1 = new Point();
p2 = new Point();

A4つのint型引数

4つのデータを「x1」「y1」「x2」「y2」の順で受け取ります。

TwoPoints2(int x1, int y1, int x2, int y2)
p1 = new Point(x1, y1);
p2 = new Point(x2, y2);

B2つのPointクラスの引数

2つのPointクラスのオブジェクトを受け取ります。

TwoPoints2(point p1, point p2)

仮引数「p1」「p2」とフィールドの変数名「p1」「p2」が同じ名前なので、フィールドの方には「this」を付けます。

整此処では実引数として与えるインスタンス化したオブジェクトとは、別の領域を確保し、其処へ実引数の値をコピーしています。

this.p1 = new Point(p1);
this.p2 = new Point(p2);

メソッドの設計

@セッタメソッド

2点の中1点を設定するのに、PointクラスsetLocationメソッドを使う事にしましょう。

Aゲッタメソッド

2点の中1点の座標を得ます。
元々フィールドがPointクラスのオブジェクトで構成されていますので、此を戻り値にします。

B操作メソッド

直線を引くメソッドを作ります。
Pointクラスのフィールドは「x」「y」ですから、

点1のx座標はp1.x
点1のy座標はp1.y
点2のx座標はp2.x
点2のy座標はp2.y

で表せます。

自分のクラスのオブジェクトを受け取るメソッド

ターゲットのオブジェクトに対し、別のオブジェクトが等しいかどうかを調べるメソッド「equals()」を作ります。
「2つのオブジェクトが等しい」とは、フィールドの全ての値が等しいと言う意味です。
メソッドにとって、ターゲットのオブジェクトは「自分」です。
そして、仮引数で受け取ったオブジェクトは「自分」と型は同じですが、「別の人」です。
メソッド内では、「自分」の事は「this」、「別の人」の事は仮引数名で呼びます。

同名でも異なるクラスに所属するメソッド

此のクラスでは、メンバが2つのPointクラスで構成されていますので、各メンバが等しいかどうかを調べるには、Pointクラスのequalsメソッドを使う事にしましょう。
今作っているメソッドと名前は同じですが所属するクラスが違う為、内容は全く別のメソッドです。
「自分」のPointクラスメンバに対し、仮引数で指定されたオブジェクトのPointクラスメンバが等しいかどうかを比べます。

this.p1.equals(obj.p1)
this.p2.equals(obj.p2)

オブジェクトを交換

先ず、データとデータを交換する手法について、変数を例に考えてみましょう。
現在int型変数「x」と「y」にそれぞれデータが記憶されているとします。
此を交換するには、

x = y;
y = x;

で良いでしょうか?

x = y;

を実行すると、「y」の内容が「x」に代入され、「x」の元の値は失われて終います。
其れから、

y = x;

を実行しても、「x」も「y」も「20」になって終います。
データの交換には「x」の値を取っておく、新たな変数が必要なのです。
つまり次の様な手順で行います。

@「x」の内容をワークエリアに退避
A「y」の値を「x」に代入
B予め退避しておいた元の「x」の値を「y」に代入して完成

以上をプログラムにすると、

temp = x;
x = y;
y = temp;

となります。
此は、オブジェクトにも適用出来ます。

メソッド内で定義する同じクラスのオブジェクト

ターゲットとなるオブジェクト「this」と、仮引数で指定されたオブジェクト「temp」をメソッド内で宣言する必要が有ります。
交換は下の例の様に行います。

「temp」はメソッド内で宣言し、インスタンス化します。

@オブジェクト「temp」のインスタンス化

TwoPoints2 temp = new TwoPoints2();

Aオブジェクト「temp」がオブジェクト「obj」の持つPointクラスのオブジェクトを指す様に

temp.p1 = obj.p1;
temp.p2 = obj.p2;

Bオブジェクト「obj」がオブジェクト「this」の持つクラスのオブジェクトを指す様に

obj.p1 = this.p1;
obj.p2 = this.p2;

Cオブジェクト「this」がオブジェクト「temp」の持つPointクラスのオブジェクトを指す様に

this.p1 = temp.p1;
this.p2 = temp.p2;
ソース ダウンロード
TwoPoints2Test.java TwoPoints02.zip
HouseCA3.java

戻る