class Point2D { double x,y; // Point2Dのインスタンス変数を初期化するためのインスタンスメソッド void initialize(double xx,double yy){ this.x=xx; this.y=yy; } double length(){ return Math.sqrt(x*x+y*y); } double distance2D(Point2D point2){ double dx=(x-point2.x),dy=(y-point2.y); return Math.sqrt(dx*dx+dy*dy); } } class ObjectTest5 { public static void main(String[] args){ Point2D p1,p2,p3; // Point2Dクラスのインスタンスを作成する p1=new Point2D(); // インスタンス変数の中身を初期化する。 p1.initialize(0.0,0.0); p2=new Point2D(); p2.initialize(1.0,1.0); p3=new Point2D(); p3.initialize(0.0,1.0); System.out.println("length of p1 = "+p1.length()); System.out.println("length of p2 = "+p2.length()); System.out.println("length of p3 = "+p3.length()); System.out.println("distance between p1 and p2 "+p1.distance2D(p2)); System.out.println("distance between p2 and p3 "+p2.distance2D(p3)); System.out.println("distance between p3 and p1 "+p3.distance2D(p1)); } }となる.このようにオブジェクトの作成と初期化のためのメソッド呼び出しは, 連携しておこなわれることが多い.
そのため,クラスの定義中にコンストラクタ(constructor,構築子と訳される こともある)と呼ばれる特別なメソッドを作っておいて,「new クラス名(引数 1, .. , 引数n)」としてオブジェクトを作ると引数の型が合うコンストラクタ が呼ばれるようにできる.コンストラクタは通常のメソッドのように,返り値 を持たない(void 型の返り値を持つとも言えるが,void とは書かない)
コンストラクタを使って,書き直したのが以下のプログラムである(コンスト ラクタの中での「this.」は省略して書いた.省略しないで書いても問題ない).
class Point2D { double x,y; // Point2Dクラスのコンストラクタ((double,double)型の引数を持つ場合)の宣言 Point2D(double xx,double yy){ x=xx; y=yy; } double length(){ return Math.sqrt(x*x+y*y); } double distance2D(Point2D point2){ double dx=(x-point2.x),dy=(y-point2.y); return Math.sqrt(dx*dx+dy*dy); } } class ObjectTest5 { public static void main(String[] args){ Point2D p1,p2,p3; // Point2Dクラスのインスタンスをコンストラクタを呼び出して作成する。 p1=new Point2D(0.0,0.0); p2=new Point2D(1.0,1.0); p3=new Point2D(0.0,1.0); System.out.println("length of p1 = "+p1.length()); System.out.println("length of p2 = "+p2.length()); System.out.println("length of p3 = "+p3.length()); System.out.println("distance between p1 and p2 "+p1.distance2D(p2)); System.out.println("distance between p2 and p3 "+p2.distance2D(p3)); System.out.println("distance between p3 and p1 "+p3.distance2D(p1)); } }
オブジェクトが作られる際に呼ばれるコンストラクタ(constructor)に対応す るものとして,オブジェクトが不要になって捨てられる際に呼ばれるファイナ ライザ(finalizer,C++などではデストラクタ(destructor)と言われるもの) があるが,それほど出てこない. |
class T{ public static void main(String[] args){ int table[]={1,2,3,1,2}; // ^^^^^^^^^^^ これが配列の初期化 System.out.println("Hello World"); // ^^^^^^^^^^^^^ これが文字列定数 } }オブジェクトはヒープ領域というところに置かれる。変数はローカル変数(メ ソッド内の変数)、インスタンス変数、クラス変数等によって置かれる場所が違 うが、オブジェクト型の変数はオブジェクトへの参照だけを持つ小さい(1ワー ドの)箱となっている。
例として、
class Point{ int x,y; Point(int xx, int yy){ x=xx; y=yy; } }で、
Point p1=new Point(1,2);とした時の絵を下に示す。
// オブジェクトの生成 Point p1=new Point(1,2); // 代入ではオブジェクトを新たに生成せず // 参照のみコピーしたので、p2とp1は同じところを指すようになる Point p2=p1; // p2を書き換え p2.x=3; // 1ではなく3が表示される System.out.println(p1.x);
class T1{ // pのxを返すがついでにp.xを1増やす static int getXandIncrement(Point p){ int x=p.x; p.x++; return x; } public static void main(String args[]){ Point p1=new Point (1,3); // 1を表示する System.out.println(getXandIncrement(p1)); // 2を表示する System.out.println(p1.x); } }このことを考えると、演算子 == がオブジェクトの同一性を表すという意味が分かってく るかもしれない。
class Point { int x,y; Point(int xx,int yy){ this.x=xx; this.y=yy; } // public boolean equals(Point p){ // return x==p.x && y==p.y; // } } class t{ public static void main(String[] args){ Point p1=new Point(0,1); Point p2=new Point(0,1); // == は同一性を表すので falseになる System.out.println(p1==p2); // == は同一性を表すので trueになる System.out.println(p1==p1); // == は同一性を表すので trueになる System.out.println(p2==p2); // Point クラスで equalsが定義していない時は == と同じ System.out.println(p1.equals(p1)); // equalsは同値性を表すように定義するので true にしたいが、 System.out.println(p1.equals(p2)); } }上の例でPointのequalsは未定義だが、Java言語のすべてのクラスは java.lang.Object という名前のクラスのサブクラスとなっていて、その中で equalsは class Object { .... public boolean equals(Object o){ return this==o; } }のように定義されているため、そのようになっている。 |
ここで、述べたオブジェクトと参照の関係は多くのオブジェクト指向言語でも
通用する議論だが、世の中でよく使われる C++ という言語では成り立たない。
C++では代入やメソッドへの引数渡しなどいたるところで、オブジェクトが作ら
れる。
C++では演算子のオーバーライドという機能が用意されていて、この機能を利用して 演算子 == は同一性を表すのではなく、同値性を表すように定義されているのが普 通である。 |