+ // Objects may be passed to methods.
+ class Test {
+ int a/ b;
+ Test(int i/ int j ){
+ a = i;
+ b = j;
+ }
+
+ // return true if o is equal to the invoking object
+ boolean equals(Test o ){
+ if(o.a == a && o.b == b )return true;
+ else return false;
+ }
+ }
+
+ class PassOb {
+ public static void main(String args[] ){
+ Test ob1 = new Test(100/ 22);
+
+ Test ob2 = new Test(100/ 22);
+ Test ob3 = new Test-(1/- 1);
+
+ System.out.println("ob1 == ob2 :" + ob1.equals(ob2));
+
+ System.out.println("ob1 == ob3 :" + ob1.equals(ob3));
+ }
+ }


اين برنامه ، خروجي بعدي را توليد مي كند :

ob1 == ob2 :true
ob1 == ob3 :false


همانطوريكه مشاهده ميكنيد، روش ()equals داخل Test دو شي ئ را از نظر كيفيت
مقايسه نموده و نتيجه را برمي گرداند . يعني اين روش ، شي ئ فراخواننده را با
شيئي كه گذر كرده مقايسه مي كند . اگر محتوي آندو يكسان باشد ، آنگاه روش true
را برمي گرداند . در غير اينصورت false را برمي گرداند . توجه داشته باشيد كه
پارامتر o در ()equals مشخص كننده Test بعنوان نوع آن مي باشد. اگرچه Test يك
نوع كلاس ايجاد شده توسط برنامه است ،اما بعنوان انواع توكار جاوا و بهمان روش
مورد استفاده قرار گرفته است .
يكي از رايجترين كاربردهاي پارامترهاي شيئي مربوط به سازندگان است . غالبا"
ممكن است بخواهيد يك شي ئ جديد را بسازيد طوري كه اين شي ئ در ابتدا نظير يك شي ئ
موجود باشد. براي انجام اينكار بايد يك تابع سازنده تعريف نماييد كه يك شي ئ از
كلاس خود را بعنوان يك پارامتر انتخاب مي كند . بعنوان مثال ، روايت بعدي از
()Box به يك شي ئ امكان داده تا آغازگر ديگري باشد :

+ // Here/ Box allows one object to initialize another.
+ class Box {
+ double width;
+ double height;
+ double depth;
+
+ // construct clone of an object
+ Box(Box ob ){ // pass object to constructor
+ width = ob.width;
+ height = ob.height;
+ depth = ob.depth;
+ }
+
+ // constructor used when all dimensions specified
+ Box(double w/ double h/ double d ){
+ width = w;
+ height = h;
+ depth = d;
+ }
+
+ // constructor used when no dimensions specified
+ Box )({
+ width =- 1; // use- 1 to indicate
+ height =- 1; // an uninitialized
+ depth =- 1; // box
+ }
+
+ // constructor used when cube is created
+ Box(double len ){
+ width = height = depth
+ }
+
+ // compute and return volume
+ double volume )({
+ return width * height * depth;
+ }
+ }
+
+ class OverloadCons2 {
+ public static void main(String args[] ){
+ // create boxes using the various constructors
+ Box mybox1 = new Box(10/ 20/ 15);
+ Box mybox2 = new Box)(;
+ Box mycube = new Box(7);
+
+ Box myclone = new Box(mybox1);
+
+ double vol;
+
+ // get volume of first box
+ vol = mybox1.volume)(;
+ System.out.println("Volume of mybox1 is " + vol);
+
+ // get volume of second box
+ vol = mybox2.volume)(;
+ System.out.println("Volume of mybox2 is " + vol);
+
+ // get volume of cube
+ vol = mycube.volume)(;
+ System.out.println("Volume of cube is " + vol);
+
+ // get volume of clone
+ vol = myclone.volume)(;
+ System.out.println("Volume of clone is " + vol);
+ }
+ }


بعدا" خواهيد ديد كه وقتي شروع به ايجاد كلاسهاي خود مي نماييد، معمولا" براي
اينكه اجازه دهيم تا اشيائ بصورتي موثر و آسان ساخته شوند ، لازم است اشكال هاي سازنده را فراهم آوريم .


نگاهي دقيق تر به گذر دادن آرگومانها

در كل ، دو راه وجود دارد تا يك زبان كامپيوتري يك آرگومان را به يك زير
روال گذر دهد. اولين راه " فراخواني بوسيله مقدار "(call-by-value() است . اين
روش مقدار يك آرگومان را در پارامتر رسمي زير روال كپي مي كند . بنابراين
تغييراتي كه روي پارامتر زير روال اعمال مي شود ، تاثيري بر آرگوماني كه براي
فراخواني آن استفاده شده نخواهد داشت . دومين راهي كه يك آرگومان مي تواند گذر
كند " فراخواني بوسيله ارجاع "(call-by-reference() است . در اين روش ، ارجاع
به يك آرگومان ( نه مقدار آن آرگومان ) به پارامتر گذر داده مي شود . داخل زير
روال از اين ارجاع براي دسترسي به آرگومان واقعي مشخص شده در فراخواني استفاده
مي شود . اين بدان معني است كه تغييرات اعمال شده روي پارامتر ، روي آرگوماني
كه براي فراخواني زير روال استفاده شده ، تاثير خواهد داشت . خواهيد ديد كه
جاوا از هر دو روش برحسب اينكه چه چيزي گذر كرده باشد ، استفاده مي كند .
در جاوا ، وقتي يك نوع ساده را به يك روش گذر مي دهيد ، اين نوع بوسيله
مقدارش گذر ميكند . بنابراين ، آنچه براي پارامتري كه آرگومان را دريافت ميكند
اتفاق بيفتد هيچ تاثيري در خارج از روش نخواهد داشت . بعنوان مثال ، برنامه
بعدي را در نظر بگيريد :

+ // Simple types are passed by value.
+ class Test {
+ void meth(int i/ int j ){
+ i *= 2;
+ j /= 2;
+ }
+ }
+
+ class CallByValue {
+ public static void main(String args[] ){
+ Test ob = new Test)(;
+ int a = 15/ b = 20;
+
+ System.out.println("a and b before call :" +
+ a + " " + b);
+
+ ob.meth(a/ b);
+
+ System.out.println("a and b after call :" +
+ a + " " + b);
+ }
+ }


خروجي برنامه فوق بقرار زير مي باشد :

a and b before call :15 20
a and b after call :15 20


بخوبي مشاهده مي كنيد كه عمليات اتفاق افتاده داخل ()meth هيچ تاثيري روي
مقادير aو bو در فراخواني استفاده شده اند، نخواهد داشت . در اينجا مقادير آنها
به 30 و 10 تغيير نمي يابد .
وقتي يك شي ئ را به يك روش گذر مي دهيد ، شرايط بطور مهيجي تغيير مي كند
زيرا اشيائ بوسيله ارجاعشان گذر داده مي شوند . بياد آوريد كه وقتي يك متغير
از يك نوع كلاس ايجاد مي كنيد ، شما فقط يك ارجاع به شي ئ خلق مي كنيد . بدين
ترتيب ، وقتي اين ارجاع را به يك روش گذر مي دهيد ، پارامتري كه آن را دريافت
مي كند . بهمان شي ئ ارجاع مي كند كه توسط آرگومان به آن ارجاع شده بود . اين
بدان معني است كه اشيائ با استفاده از طريقه " فراخواني بوسيله ارجاع " به
روشها گذر داده مي شوند. تغييرات اشيائ داخل روش سبب تغيير شيئي است كه بعنوان
يك آرگومان استفاده شده است . بعنوان مثال ، برنامه بعدي را در نظر بگيريد :

+ // Objects are passed by reference.
+
+ class Test {
+ int a/ b;
+
+ Test(int i/ int j ){
+ a = i;
+ b = j;
+ }
+
+ // pass an object
+ void meth(Test o ){
+ o.a *= 2;
+ o.b /= 2;
+ }
+ }
+
+ class CallByRef {
+ public static void main(String args[] ){
+ Test ob = new Test(15/ 20);
+
+ System.out.println("ob.a and ob.b before call :" +
+ ob.a + " " + ob.b);
+
+ ob.meth(ob);
+
+ System.out.println("ob.a and ob.b after call :" +
+ ob.a + " " + ob.b);


برنامه فوق ، خروجي زير را توليد مي كند :

ob.a and ob.b before call :15 20
ob.a and ob.b after call :30 10


همانطوريكه مي بينيد ، در اين حالت ، اعمال داخل ()meth ، شيئي را كه بعنوان
يك آرگومان استفاده شده تحت تاثير قرار داده است .
يك نكته جالب توجه اينكه وقتي يك ارجاع شي ئ به يك روش گذر داده مي شود، خود
ارجاع از طريق " فراخواني بوسيله مقدار " گذر داده مي شود . اما چون مقداري كه
بايد گذر داده شود خودش به يك شي ئ ارجاع مي كند ، كپي آن مقدار همچنان به همان
شي ئ ارجاع مي كند كه آرگومان مربوطه ارجاع مي كند .
ياد آوري : وقتي يك نوع ساده به يك روش گذر داده ميشود اينكار توسط " فراخواني
بوسيله مقدار " انجام ميگيرد. اشيائتوسط " فراخواني بوسيله ارجاع "
گذر داده مي شوند .

برگرداندن اشيائ
يك روش قادر است هر نوع داده شامل انواع كلاسي كه ايجاد ميكنيد را برگرداند.
بعنوان مثال ، در برنامه بعدي روش ()incrByTen يك شي ئ را برمي گرداند كه در آن
مقدار a ده واحد بزرگتر از مقدار آن در شي ئ فراخواننده است .

+ // Returning an object.
+ class Test {
+ int a;
+
+ Test(int i ){
+ a = i;
+ }
+
+ Test incrByTen )({
+ Test temp = new Test(a+10);
+ return temp;
+ }
+ }
+
+ class RetOb {
+ public static void main(String args[] ){
+ Test ob1 = new Test(2);
+ Test ob2;
+ ob2 = ob1.incrByTen)(;
+ System.out.println("ob1.a :" + ob1.a);
+ System.out.println("ob2.a :" + ob2.a);
+
+ ob2 = ob2.incrByTen)(;
+ System.out.println("ob2.a after second increase :"
+ + ob2.a);
+ }
+ }


خروجي برنامه فوق بقرار زير مي باشد :

ob1.a :2
ob2.a :12
ob2.a after second increase :22


همانطوريكه مشاهده مي كنيد ، هر بار كه ()incrByTen فراخوانده مي شود ، يك
شي ئ جديد توليد شده و يك ارجاع به آن شي ئ جديد به روال فراخواننده برگردان
مي شود .
مثال قبلي يك نكته مهم ديگر را نشان ميدهد : از آنجاييكه كليه اشيائ بصورت
پويا و با استفاده از new تخصيص مي يابند ، نگراني راجع به شيئي كه خارج از
قلمرو برود نخواهيد داشت ، زيرا در اين صورت روشي كه شي ئ درآن ايجاد شده پايان
خواهد گرفت . يك شي ئ ماداميكه از جايي در برنامه شما ارجاعي به آن وجود داشته
باشد ، زنده خواهد ماند . وقتي كه ارجاعي به آن شي ئ وجود نداشته باشد ، دفعه مرمت خواهد شد .