9.クラスの機能
Copyright(C) 30Sep2013 coskx
クラスには1つのデータの塊を操作するだけでなく,拡張したデータの塊の操作を記述する方法も備わっている。
ここで修得してほしい内容は以下の通りである。
1.クラスの継承。
2.ポリモフィズム。
3.抽象クラス
4.インターフェイス
9.1 クラスの継承 |
---|
クラスを作成してゆくと,似たものクラスを作成することがある。似たものクラスには全く同じメンバ変数やメソッドを含む。先に作ったものを流用し,同じことは書かないようにする方法がある。これはクラスの継承と呼ばれる記述方法を使う。クラスの継承はあまり小さなプログラム例ではご利益がわかりにくいので,少々大きなプログラムをあつかう。
次に取り上げる例では,まず,(9.1.1)にてxy座標を与えるとコンソール画面に座標軸と点xyを表示するからくりを与えるクラスを作る。次に,(9.1.2)で似たようなクラスとして,xy座標を与えるとコンソール画面に座標軸と「点xyと点(0,0)を対角線とする長方形」を表示するからくりを与えるクラスを,継承を利用して作る。
舞台装置としては,コンソール画面用クラスが1つ,コンソール画面用インスタンスが1つ,
点を表すクラスが1つ,点を表すインスタンスが2つ出てくる。
コンソール画面の大きさは横幅76,高さ32で,2つの点は(53,21),(63,14)とする。
座標軸はコンソール画面用インスタンスで用意する。
クラスPoint内のprivate宣言されたメンバ変数は,クラスChardraw0からアクセスできない。
List 9.1.1 xy座標を与え,コンソール画面に座標軸と点xyを表示する
ファイル名 Chardraw0.java
/* Chardraw0.java */
class Point {
private int x; /* x座標 */
private int y; /* y座標 */
Point() { /*引数なしコンストラクタ*/
}
Point(int x, int y) { /*引数付コンストラクタ*/
this.x=x; /*受け取ったxを自分自身のxに格納*/
this.y=y;
}
public void print() {
System.out.printf("Point x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
public void puton(ConsoleDisplay cns) {
if (0<x && x<cns.width && 0<y && y<cns.height) {
cns.ary[y][x]='*';
}
}
}
class ConsoleDisplay {
int width, height;
char[][] ary;
ConsoleDisplay(){
}
ConsoleDisplay(int width, int height){
this.width=width; /*受け取ったwidthを自分自身のwidthに格納*/
this.height=height;
ary = new char[height][width];
fillAry();
}
/*座標系の舞台装置を2次元配列上に作る*/
private void fillAry() {
int i,j;
char ch;
for (i=0; i<height; i++) {
for (j=0; j<width; j++) {
ary[i][j]=' ';
}
}
for (j=0; j<width; j++) {
if (j%10==0) ch=(char)(j/10+'0');
else if (j%5==0) ch='+';
else ch='-';
ary[0][j]=ch;
}
for (j=0; j<height; j++) {
if (j%10==0) ch=(char)(j/10+'0');
else if (j%5==0) ch='+';
else ch='|';
ary[j][0]=ch;
}
}
/*受け取ったPointのインスタンスに自分(ConsoleDisplay)の*/
/*インスタンスを与えて点を載せてもらう*/
public void setShape(Point mypnt) {
mypnt.puton(this);
}
/*出来上がったコンソールを表示する*/
public void show() {
int i,j;
for (i=0; i<height; i++) {
for (j=0; j<width; j++) {
System.out.print(ary[i][j]);
}
System.out.println();
}
System.out.println();
}
}
class Chardraw0 {
public static void main(String args[]) {
Chardraw0 mainprg = new Chardraw0();
}
Chardraw0() {
Point mypoint1 = new Point(53,21);
Point mypoint2 = new Point(63,14);
ConsoleDisplay mycon= new ConsoleDisplay(76,32);
mypoint1.print();
mypoint2.print();
mycon.setShape(mypoint1);
mycon.setShape(mypoint2);
mycon.show();
}
}
実行結果((53,21),(63,14)に*が表示されている) >java Chardraw0
Point x=53 y=21
Point x=63 y=14
0----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
|
|
|
|
+
|
|
|
|
1
|
|
|
| *
+
|
|
|
|
2
| *
|
|
|
+
|
|
|
|
3
|
1)スーパークラスで宣言されたメンバ変数,メソッドのうち,
サブクラスで宣言されていないメンバ変数,メソッドは,
あたかもサブクラス内に定義されているようにふるまう。
2)スーパークラスでprotected宣言されたメンバ変数,メソッドは,
自クラスおよびサブクラスからのみアクセスできる。
(protect 宣言されたものは同じパッケージ内からもアクセス可能)
(private宣言されたものは自クラスのみからしかアクセスできない。)
3)サブクラス内でスーパークラスのメソッドと同じ名前のメソッドを記述すると,
サブクラス内からはスーパークラス内のメソッドではなく,
自クラスのメソッドが使えるようになる。
このことをメソッドのオーバーライドと呼ぶ。
メンバ変数のオーバーライドは厳密にいうとできないと考えるのがよい。
4)同じクラス内で,同じ名前のメソッドで,引数が異なる場合は,メソッドの
オーバーロードと呼ばれる。(引数が異なれば違うメソッドと認識される。)
5)サブクラスのコンストラクタが呼び出された時には,
スーパークラスのデフォルトコンストラクタ(引数なしコンストラクタ)
も自動的に呼び出される。以下のプログラムもこのことを利用している。
たとえば,main中で, Rectangle rect= new Rectangle(20,10);は
class RectangleのコンストラクタRectangle(int x, int y)を呼び出しているが
この時,自動的にスーパークラスclass Pointの引数なしコンストラクタが呼び出
されている。(ここでは意味はない)
class FilledRectangleのprint()とputon(ConsoleDisplay cns)の定義のところに,@Overrideが宣言されている。この宣言はなくても構わない。@Override宣言はそのメソッドがスーパークラスの同じシグネチャの関数をオーバーライドしていることを明示している。
List 9.1.2 xy座標を与え,コンソール画面に長方形を表示する複数の継承クラス
ファイル名 Chardraw1.java/* Chardraw1.java */
class Point {
protected int x; /* x座標 */
protected int y; /* y座標 */
Point() { /*引数なしコンストラクタ*/
}
Point(int x, int y) { /*引数付コンストラクタ*/
this.x=x; /*受け取ったxを自分自身のxに格納*/
this.y=y;
}
public void print() {
System.out.printf("Point x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
public void puton(ConsoleDisplay cns) {
if (0<x && x<cns.width && 0<y && y<cns.height) {
cns.ary[y][x]='*';
}
}
}
class Rectangle extends Point {
Rectangle() { /*引数なしコンストラクタ*/
}
Rectangle(int x, int y) { /*引数付コンストラクタ*/
this.x=x;
this.y=y;
}
public void print() {
System.out.printf("Rectangle x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
public void puton(ConsoleDisplay cns) {
int i;
if (0<x && x<cns.width && 0<y && y<cns.height) {
for (i=1; i<=x; i++) {
cns.ary[1][i]='*';
cns.ary[y][i]='*';
}
for (i=1; i<=y; i++) {
cns.ary[i][1]='*';
cns.ary[i][x]='*';
}
}
}
}
class FilledRectangle extends Point {
FilledRectangle() { /*引数なしコンストラクタ*/
}
FilledRectangle(int x, int y) { /*引数付コンストラクタ*/
this.x=x;
this.y=y;
}
@Override public void print() {
System.out.printf("FilledRectangle x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
@Override public void puton(ConsoleDisplay cns) {
int i,j;
if (0<x && x<cns.width && 0<y && y<cns.height) {
for (i=1; i<=y; i++) {
for (j=1; j<=x; j++) {
cns.ary[i][j]='*';
}
}
}
}
}
class ConsoleDisplay {
int width, height;
char[][] ary;
ConsoleDisplay(){
}
ConsoleDisplay(int width, int height){
this.width=width; /*受け取ったwidthを自分自身のwidthに格納*/
this.height=height;
ary = new char[height][width];
fillAry();
}
/*座標系の舞台装置を2次元配列上に作る*/
private void fillAry() {
int i,j;
char ch;
for (i=0; i<height; i++) {
for (j=0; j<width; j++) {
ary[i][j]=' ';
}
}
for (j=0; j<width; j++) {
if (j%10==0) ch=(char)(j/10+'0');
else if (j%5==0) ch='+';
else ch='-';
ary[0][j]=ch;
}
for (j=0; j<height; j++) {
if (j%10==0) ch=(char)(j/10+'0');
else if (j%5==0) ch='+';
else ch='|';
ary[j][0]=ch;
}
}
/*受け取ったPointのインスタンスに自分(ConsoleDisplay)の*/
/*インスタンスを与えて点を載せてもらう*/
public void setShape(Point mypnt) {
mypnt.puton(this);
}
/*受け取ったRectangleのインスタンスに自分(ConsoleDisplay)の*/
/*インスタンスを与えて点を載せてもらう*/
public void setShape(Rectangle myrec) {
myrec.puton(this);
}
/*受け取ったFilledRectangleのインスタンスに自分(ConsoleDisplay)の*/
/*インスタンスを与えて点を載せてもらう*/
public void setShape(FilledRectangle myfrec) {
myfrec.puton(this);
}
/*出来上がったコンソールを表示する*/
public void show() {
int i,j;
for (i=0; i<height; i++) {
for (j=0; j<width; j++) {
System.out.print(ary[i][j]);
}
System.out.println();
}
System.out.println();
}
}
class Chardraw1 {
public static void main(String args[]) {
Chardraw1 mainprg = new Chardraw1();
}
Chardraw1() {
Point mypoint1 = new Point(53,21);
Point mypoint2 = new Point(63,14);
Rectangle myrec1= new Rectangle(43,12);
Rectangle myrec2= new Rectangle(53,8);
FilledRectangle myfrec= new FilledRectangle(13,18);
ConsoleDisplay mycon= new ConsoleDisplay(76,32);
mypoint1.print();
mypoint2.print();
myrec1.print();
myrec2.print();
myfrec.print();
mycon.setShape(mypoint1);
mycon.setShape(mypoint2);
mycon.setShape(myrec1);
mycon.setShape(myrec2);
mycon.setShape(myfrec);
mycon.show();
}
}
実行結果 >java Chardraw1
Point x=53 y=21
Point x=63 y=14
Rectangle x=43 y=12
Rectangle x=53 y=8
FilledRectangle x=13 y=18
0----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
|*****************************************************
|************* * *
|************* * *
|************* * *
+************* * *
|************* * *
|************* * *
|*****************************************************
|************* *
1************* *
|************* *
|*******************************************
|*************
|************* *
+*************
|*************
|*************
|*************
|
2
| *
|
|
|
+
|
|
|
|
3
|
List 9.1.3 サブクラスのインスタンスの生成時に呼び出されるコンストラクタ
ファイル名 Constructor.java/* Constructor.java */
class MySuper { /*スーパークラス*/
MySuper() { /*スーパークラスのコンストラクタ*/
System.out.println("This is MySuper default constructor.");
}
}
class MySub extends MySuper { /*サブクラス*/
String str;
MySub() { /*サブクラスのコンストラクタ*/
System.out.println("This is MySub default constructor.");
}
MySub(String s) {
System.out.println("This is MySub constructor with String s.");
str=s;
}
}
class Constructor {
public static void main(String args[]) {
Constructor mainprg = new Constructor();
}
Constructor() {
System.out.println("main1");
MySuper spr= new MySuper();
System.out.println("main2");
MySub sub= new MySub();
System.out.println("main3");
MySub sub2= new MySub("Hello");
System.out.println("main4");
}
}
/******** 実行結果 *********
>java constructor
main1
This is MySuper default constructor.
main2
This is MySuper default constructor. ←この部分が自動呼出しの証拠
This is MySub default constructor.
main3
This is MySuper default constructor. ←この部分が自動呼出しの証拠
This is MySub constructor with String s.
main4
****************************/
課題 9.1 |
---|
9.2 インスタンスのキャスト |
---|
サブクラスのインスタンスを作成しておきながら,スーパークラスのインスタンス変数に参照を代入するとどうなるかを見てみよう。
List 9.2.1 インスタンスのキャスト クラスの定義部分はList 9.1.2と同じ(薄い色のところ)
ファイル名 Chardraw2.java/* Chardraw2.java */
class Point {
protected int x; /* x座標 */
protected int y; /* y座標 */
Point() { /*引数なしコンストラクタ*/
}
Point(int x, int y) { /*引数付コンストラクタ*/
this.x=x; /*受け取ったxを自分自身のxに格納*/
this.y=y;
}
public void print() {
System.out.printf("Point x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
public void puton(ConsoleDisplay cns) {
if (0<x && x<cns.width && 0<y && y<cns.height) {
cns.ary[y][x]='*';
}
}
}
class Rectangle extends Point {
Rectangle() { /*引数なしコンストラクタ*/
}
Rectangle(int x, int y) { /*引数付コンストラクタ*/
this.x=x;
this.y=y;
}
public void print() {
System.out.printf("Rectangle x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
public void puton(ConsoleDisplay cns) {
int i;
if (0<x && x<cns.width && 0<y && y<cns.height) {
for (i=1; i<=x; i++) {
cns.ary[1][i]='*';
cns.ary[y][i]='*';
}
for (i=1; i<=y; i++) {
cns.ary[i][1]='*';
cns.ary[i][x]='*';
}
}
}
}
class FilledRectangle extends Point {
FilledRectangle() { /*引数なしコンストラクタ*/
}
FilledRectangle(int x, int y) { /*引数付コンストラクタ*/
this.x=x;
this.y=y;
}
@Override public void print() {
System.out.printf("FilledRectangle x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
@Override public void puton(ConsoleDisplay cns) {
int i,j;
if (0<x && x<cns.width && 0<y && y<cns.height) {
for (i=1; i<=y; i++) {
for (j=1; j<=x; j++) {
cns.ary[i][j]='*';
}
}
}
}
}
class ConsoleDisplay {
int width, height;
char[][] ary;
ConsoleDisplay(){
}
ConsoleDisplay(int width, int height){
this.width=width; /*受け取ったwidthを自分自身のwidthに格納*/
this.height=height;
ary = new char[height][width];
fillAry();
}
/*座標系の舞台装置を2次元配列上に作る*/
private void fillAry() {
int i,j;
char ch;
for (i=0; i<height; i++) {
for (j=0; j<width; j++) {
ary[i][j]=' ';
}
}
for (j=0; j<width; j++) {
if (j%10==0) ch=(char)(j/10+'0');
else if (j%5==0) ch='+';
else ch='-';
ary[0][j]=ch;
}
for (j=0; j<height; j++) {
if (j%10==0) ch=(char)(j/10+'0');
else if (j%5==0) ch='+';
else ch='|';
ary[j][0]=ch;
}
}
/*受け取ったPointのインスタンスに自分(ConsoleDisplay)の*/
/*インスタンスを与えて点を載せてもらう*/
public void setShape(Point mypnt) {
mypnt.puton(this);
}
/*受け取ったRectangleのインスタンスに自分(ConsoleDisplay)の*/
/*インスタンスを与えて点を載せてもらう*/
public void setShape(Rectangle myrec) {
myrec.puton(this);
}
/*受け取ったFilledRectangleのインスタンスに自分(ConsoleDisplay)の*/
/*インスタンスを与えて点を載せてもらう*/
public void setShape(FilledRectangle myfrec) {
myfrec.puton(this);
}
/*出来上がったコンソールを表示する*/
public void show() {
int i,j;
for (i=0; i<height; i++) {
for (j=0; j<width; j++) {
System.out.print(ary[i][j]);
}
System.out.println();
}
System.out.println();
}
}
class Chardraw2 {
public static void main(String args[]) {
Chardraw2 mainprg = new Chardraw2();
}
Chardraw2() {
Point mypoint1 = new Point(53,21);
Point mypoint2= new Rectangle(43,12);
ConsoleDisplay mycon= new ConsoleDisplay(76,32);
mypoint1.print();
mypoint2.print();
mycon.setShape(mypoint1);
mycon.setShape(mypoint2);
mycon.show();
}
}
Point mypoint1 = new Point(53,21);
では,class Pointのインスタンスの参照をclass Pointのインスタンス変数に代入している。
インスタンス変数mypoint1には53と21からなるclass PointのインスタンスのIDが保存される。
*1 IDを知ることができないのでxxxxxxxxと表した。
class Pointのインスタンス変数名 値 mypoint1 ID xxxxxxxx *1
class Pointのインスタンス (ID xxxxxxxx) メンバ変数名 値 x 53 y 21
Point mypoint2= new Rectangle(43,12);
*2 IDを知ることができないのでyyyyyyyyと表した。
class Pointのインスタンス変数名 値 mypoint2 ID yyyyyyyy *2
class Rectangleのインスタンス (ID yyyyyyyy) メンバ変数名 値 x 43 y 12
この状態で
実行結果 Point x=53 y=21
Rectangle x=43 y=12
0----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
|*******************************************
|* *
|* *
|* *
+* *
|* *
|* *
|* *
|* *
1* *
|* *
|*******************************************
|
|
+
|
|
|
|
2
| *
|
|
|
+
|
|
|
|
3
|
この結果のように,mypoint2.print();ではclass Rectangleのprint()が動作した。
また,mycon.setShape(mypoint2);ではclass ConsoleDisplay内のmycon.setShape(Rectangle myrec)が動いたことがわかる。
スーパークラスのインスタンス変数に,サブクラスのインスタンスが保存されている状態で,
メソッドを呼び出すと,インスタンスが属しているサブクラスのメソッドが起動する。
ただし,インスタンス変数が,スーパークラスに属し,インスタンスがサブクラスに属するようには出来るが,
この逆はできるとは限らない。例えば次のようになる。
class Point : スーパークラス
class Rectangle: サブクラス
○ Point px = new Rectangle(35,12);
×? Rectangle px = new Point(35,12);
9.3 ポリモーフィズム(多態性) |
---|
List 9.3.1 インスタンスのキャスト (クラスの定義部分はList 9.1.2と同じ(薄い色のところ)
ファイル名 Chardraw3.java
/* Chardraw3.java */
class Point {
protected int x; /* x座標 */
protected int y; /* y座標 */
Point() { /*引数なしコンストラクタ*/
}
Point(int x, int y) { /*引数付コンストラクタ*/
this.x=x; /*受け取ったxを自分自身のxに格納*/
this.y=y;
}
public void print() {
System.out.printf("Point x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
public void puton(ConsoleDisplay cns) {
if (0<x && x<cns.width && 0<y && y<cns.height) {
cns.ary[y][x]='*';
}
}
}
class Rectangle extends Point {
Rectangle() { /*引数なしコンストラクタ*/
}
Rectangle(int x, int y) { /*引数付コンストラクタ*/
this.x=x;
this.y=y;
}
public void print() {
System.out.printf("Rectangle x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
public void puton(ConsoleDisplay cns) {
int i;
if (0<x && x<cns.width && 0<y && y<cns.height) {
for (i=1; i<=x; i++) {
cns.ary[1][i]='*';
cns.ary[y][i]='*';
}
for (i=1; i<=y; i++) {
cns.ary[i][1]='*';
cns.ary[i][x]='*';
}
}
}
}
class FilledRectangle extends Point {
FilledRectangle() { /*引数なしコンストラクタ*/
}
FilledRectangle(int x, int y) { /*引数付コンストラクタ*/
this.x=x;
this.y=y;
}
@Override public void print() {
System.out.printf("FilledRectangle x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
@Override public void puton(ConsoleDisplay cns) {
int i,j;
if (0<x && x<cns.width && 0<y && y<cns.height) {
for (i=1; i<=y; i++) {
for (j=1; j<=x; j++) {
cns.ary[i][j]='*';
}
}
}
}
}
class ConsoleDisplay {
int width, height;
char[][] ary;
ConsoleDisplay(){
}
ConsoleDisplay(int width, int height){
this.width=width; /*受け取ったwidthを自分自身のwidthに格納*/
this.height=height;
ary = new char[height][width];
fillAry();
}
/*座標系の舞台装置を2次元配列上に作る*/
private void fillAry() {
int i,j;
char ch;
for (i=0; i<height; i++) {
for (j=0; j<width; j++) {
ary[i][j]=' ';
}
}
for (j=0; j<width; j++) {
if (j%10==0) ch=(char)(j/10+'0');
else if (j%5==0) ch='+';
else ch='-';
ary[0][j]=ch;
}
for (j=0; j<height; j++) {
if (j%10==0) ch=(char)(j/10+'0');
else if (j%5==0) ch='+';
else ch='|';
ary[j][0]=ch;
}
}
/*受け取ったPointのインスタンスに自分(ConsoleDisplay)の*/
/*インスタンスを与えて点を載せてもらう*/
/*Pointはスーパークラスなので,サブクラスのインスタンスが*/
/*やってきてもその素性に応じたメソッドputon()を呼び出す*/
public void setShape(Point mypntObj) {
mypntObj.puton(this); /*thisはこのクラス(のインスタンス)*/
}
/*出来上がったコンソールを表示する*/
public void show() {
int i,j;
for (i=0; i<height; i++) {
for (j=0; j<width; j++) {
System.out.print(ary[i][j]);
}
System.out.println();
}
System.out.println();
}
}
class Chardraw3 {
public static void main(String args[]) {
Chardraw3 mainprg = new Chardraw3();
}
Chardraw3() {
Point[] pnt = new Point[5];
pnt[0] = new Point(53,21);
pnt[1] = new Point(63,14);
pnt[2] = new Rectangle(43,12);
pnt[3] = new Rectangle(53,8);
pnt[4] = new FilledRectangle(13,18);
ConsoleDisplay mycon= new ConsoleDisplay(76,32);
int i;
for (i=0; i<5;i++) {
pnt[i].print(); /*pnt[i]の素性に応じたクラスのprint()が呼び出される*/
}
for (i=0; i<5;i++) {
mycon.setShape(pnt[i]);
}
mycon.show();
}
}
実行結果
>java Chardraw3
Point x=53 y=21
Point x=63 y=14
Rectangle x=43 y=12
Rectangle x=53 y=8
FilledRectangle x=13 y=18
0----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
|*****************************************************
|************* * *
|************* * *
|************* * *
+************* * *
|************* * *
|************* * *
|*****************************************************
|************* *
1************* *
|************* *
|*******************************************
|*************
|************* *
+*************
|*************
|*************
|*************
|
2
| *
|
|
|
+
|
|
|
|
3
|
この例のように,共通のメソッド呼び出しで,インスタンスの種類に応じて,あらかじめ決められた別々の処理を行う性質のことは,ポリモーフィズム(多態性)と呼ばれる。
9.4 抽象クラス |
---|
実行結果は9.3の実行結果と同じになる。
List 9.4.1 抽象クラスCoordinateの導入
ファイル名 Chardraw4.java/* Chardraw4.java */
abstract class Coordinate {
protected int x; /* x座標 */
protected int y; /* y座標 */
abstract public void print();
abstract public void puton(ConsoleDisplay cns);
}
class Point extends Coordinate {
Point() { /*引数なしコンストラクタ*/
}
Point(int x, int y) { /*引数付コンストラクタ*/
this.x=x; /*受け取ったxを自分自身のxに格納*/
this.y=y;
}
@Override public void print() {
System.out.printf("Point x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
@Override public void puton(ConsoleDisplay cns) {
if (0<x && x<cns.width && 0<y && y<cns.height) {
cns.ary[y][x]='*';
}
}
}
class Rectangle extends Coordinate {
Rectangle() { /*引数なしコンストラクタ*/
}
Rectangle(int x, int y) { /*引数付コンストラクタ*/
this.x=x;
this.y=y;
}
@Override public void print() {
System.out.printf("Rectangle x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
@Override public void puton(ConsoleDisplay cns) {
int i;
if (0<x && x<cns.width && 0<y && y<cns.height) {
for (i=1; i<=x; i++) {
cns.ary[1][i]='*';
cns.ary[y][i]='*';
}
for (i=1; i<=y; i++) {
cns.ary[i][1]='*';
cns.ary[i][x]='*';
}
}
}
}
class FilledRectangle extends Coordinate {
FilledRectangle() { /*引数なしコンストラクタ*/
}
FilledRectangle(int x, int y) { /*引数付コンストラクタ*/
this.x=x;
this.y=y;
}
@Override public void print() {
System.out.printf("FilledRectangle x=%d y=%d\n",x,y);
}
/*コンソール画面をもらって,その上の自分の座標に'*'を載せる*/
@Override public void puton(ConsoleDisplay cns) {
int i,j;
if (0<x && x<cns.width && 0<y && y<cns.height) {
for (i=1; i<=y; i++) {
for (j=1; j<=x; j++) {
cns.ary[i][j]='*';
}
}
}
}
}
class ConsoleDisplay {
int width, height; /*コンソール表示部の大きさ*/
char[][] ary; /**/
ConsoleDisplay(){
}
ConsoleDisplay(int width, int height){
this.width=width; /*受け取ったwidthを自分自身のwidthに格納*/
this.height=height;
ary = new char[height][width];
fillAry();
}
/*座標系の舞台装置を2次元配列上に作る*/
private void fillAry() {
int i,j;
char ch;
for (i=0; i<height; i++) {
for (j=0; j<width; j++) {
ary[i][j]=' ';
}
}
for (j=0; j<width; j++) {
if (j%10==0) ch=(char)(j/10+'0');
else if (j%5==0) ch='+';
else ch='-';
ary[0][j]=ch;
}
for (j=0; j<height; j++) {
if (j%10==0) ch=(char)(j/10+'0');
else if (j%5==0) ch='+';
else ch='|';
ary[j][0]=ch;
}
}
/*受け取ったPointのインスタンスに自分(ConsoleDisplay)の*/
/*インスタンスを与えて点を載せてもらう*/
/*Coordinateはスーパークラスなので,サブクラスのインスタンスが*/
/*やってきてもその素性に応じたメソッドputon()を呼び出す*/
public void setShape(Coordinate myObj) {
myObj.puton(this); /*thisはこのクラス(のインスタンス)*/
}
/*出来上がったコンソールを表示する*/
public void show() {
int i,j;
for (i=0; i<height; i++) {
for (j=0; j<width; j++) {
System.out.print(ary[i][j]);
}
System.out.println();
}
System.out.println();
}
}
class Chardraw4 {
public static void main(String args[]) {
Chardraw4 mainprg = new Chardraw4();
}
Chardraw4() {
Coordinate[] crd = new Coordinate[5]; //抽象クラスのインスタンスの配列
crd[0] = new Point(53,21);
crd[1] = new Point(63,14);
crd[2] = new Rectangle(43,12);
crd[3] = new Rectangle(53,8);
crd[4] = new FilledRectangle(13,18);
ConsoleDisplay mycon= new ConsoleDisplay(76,32);
int i;
for (i=0; i<5;i++) {
crd[i].print(); /*crd[i]の素性に応じたクラスのprint()が呼び出される*/
}
for (i=0; i<5;i++) {
mycon.setShape(crd[i]);
}
mycon.show();
}
}
9.5 インターフェイス |
---|
実行結果は9.3の実行結果と同じになる。
List 9.5.1 インターフェイス IF_Shapeの導入
ファイル名 Chardraw5.java/* Chardraw5.java */
interface if_Shape {
abstract public void print();
/*インスタンスが持っているx,yの値を表示してほしい*/
abstract public void puton(ConsoleDisplay cns);
/*座標系の表示とインスタンスの表すべき図形をコンソール座標平面に置く*/
}
abstract class Coordinate implements if_Shape {
protected int x; /* x座標 */
protected int y; /* y座標 */
/*原点は左上とし,右向きにx:正,下向きにy:正*/
Coordinate() { /*引数なしのコンストラクタ*/
}
Coordinate(int x, int y) { /*引数付のコンストラクタ*/
this.x=x;
this.y=y;
}
}
class Point extends Coordinate {
Point() { /*引数なしコンストラクタ*/
}
Point(int x, int y) { /*引数付コンストラクタ*/
this.x=x;
this.y=y;
}
@Override public void print() {
System.out.printf("Point x=%d y=%d\n",x,y);
}
@Override public void puton(ConsoleDisplay cns) {
cns.ary[y][x]='*';
}
}
class Rectangle extends Coordinate {
Rectangle() { /*引数なしコンストラクタ*/
}
Rectangle(int x, int y) { /*引数付コンストラクタ*/
this.x=x;
this.y=y;
}
@Override public void print() {
System.out.printf("Rectangle x=%d y=%d\n",x,y);
}
@Override public void puton(ConsoleDisplay cns) {
int i;
for (i=1; i<=x; i++) {
cns.ary[1][i]='*';
cns.ary[y][i]='*';
}
for (i=1; i<=y; i++) {
cns.ary[i][1]='*';
cns.ary[i][x]='*';
};
}
}
class FilledRectangle extends Coordinate {
FilledRectangle() { /*引数なしコンストラクタ*/
}
FilledRectangle(int x, int y) { /*引数付コンストラクタ*/
this.x=x;
this.y=y;
}
@Override public void print() {
System.out.printf("FilledRectangle x=%d y=%d\n",x,y);
}
@Override public void puton(ConsoleDisplay cns) {
int i,j;
for (i=1; i<=y; i++) {
for (j=1; j<=x; j++) {
cns.ary[i][j]='*';
}
}
}
}
class ConsoleDisplay {
int width, height;
char[][] ary;
ConsoleDisplay(){
}
ConsoleDisplay(int width, int height){
this.width=width;
this.height=height;
ary = new char[height][width];
fillAry();
}
private void fillAry() {
int i,j;
char ch;
for (i=0; i<height; i++) {
for (j=0; j<width; j++) {
ary[i][j]=' ';
}
}
for (j=0; j<width; j++) {
if (j%10==0) ch=(char)(j/10+'0');
else if (j%5==0) ch='+';
else ch='-';
ary[0][j]=ch;
}
for (j=0; j<height; j++) {
if (j%10==0) ch=(char)(j/10+'0');
else if (j%5==0) ch='+';
else ch='|';
ary[j][0]=ch;
}
}
public void setShape(if_Shape myshape) {
myshape.puton(this);
}
public void show() {
int i,j;
for (i=0; i<height; i++) {
for (j=0; j<width; j++) {
System.out.print(ary[i][j]);
}
System.out.println();
}
System.out.println();
}
}
class Chardraw5 {
public static void main(String args[]) {
Chardraw5 mainprg = new Chardraw5();
}
Chardraw5() {
if_Shape[] ifcdn= new if_Shape[5];
ifcdn[0] = new Point(53,21);
ifcdn[1] = new Point(63,14);
ifcdn[2] = new Rectangle(43,12);
ifcdn[3] = new Rectangle(53,8);
ifcdn[4] = new FilledRectangle(13,18);
ConsoleDisplay mycon= new ConsoleDisplay(76,32);
int i;
for (i=0; i<5;i++) {
ifcdn[i].print(); /*ifcdn[i]の素性に応じたクラスのprint()が呼び出される*/
}
for (i=0; i<5;i++) {
mycon.setShape(ifcdn[i]);
}
mycon.show();
}
}
課題 9 |
---|