View Full Version : مفهوم دو نکته از کتاب جاوا دیتل
mehdi_m3
سه شنبه 12 مرداد 1395, 15:18 عصر
سلام دوستان
مفهوم دو نکته از کتاب جاوا دیتل برام قابل فهم نیس. لطفا این دو نکته را برام توضیح بدین. ممنون
141824
141825
vahid-p
چهارشنبه 13 مرداد 1395, 00:43 صبح
خیلی وقت ها ما در subclass یعنی کلاسی که از کلاس دیگه ای ارث بری میکنه و اون کلاس رو extend میکنه، بعضی از متدهای supercalss رو بازنویسی میکنیم. اینکار باعث میشه هنگامی که از متدهای subclass استفاده میکنیم تمامی متدهایی که بازنویسی نشدن از متدهای superclass استفاده بشه و اگر متدی در subclass بازنویسی شده از متد بازنویسی شده به جای متد superclass استفاده میشه. این بهش میگن override.
از طرفی در موارد زیادی در متد بازنویسی شده (override شده) ما میخوایم علاوه بر کارهایی که متد اصلی (در superclass) انجام میشه، اعمال اضافه تری رو انجام بدیم. برای همین منظور میاییم و متد superclass که هم اسم متد در حال بازنویسی در subclass هست رو صدا میزنیم. اما چون هم اسم هستن، کامپایلر همیشه به نزدیکترین متد یعنی همون متد subclass مراجعه میکنه و دوباره در همین متد، خودش رو صدا میزنه و یک حلقه بی نهایت ایجاد میشه. برای اینکه در متد subclass که هم اسم متد superclass است و بخوایم متد superclass رو صدا بزنیم با عبارت super.x() این تمایز رو قائل میشیم.
یک مثال بزنم:
فرض کنید دو کلاس داریم به اسم SuperClass و SubClass:
class SuperClass(){ public void yMethod(){
System.out.println("SuperClass yMethod");
}
public void xMethod(){
System.out.println("SuperClass xMethod");
}
}
class SubClass extends SuperClass(){
public void xMethod(){
super.xMethod();
System.out.println("SubClass xMethod");
}
}
خب همونطور که میدونید SubClass دارای دو متد yMethod و xMethod هست. شما اگر مثلا subObj.yMethod() رو اجرا کنید پیام SuperClass yMethod چاپ خواهد شد و اگر subObj.xMethod() رو اجرا کنید هر دو پیام SuperClass xMethod و SubClass xMethod چاپ خواهد شد. چاپ SuperClass xMethod به خاطر super.xMethod(); بوده. حالا فرض کنید اگر به جای super.xMethod() نوشته بودیم xMethod() چی میشد؟ (کافیه امتحان کنید)
vahid-p
چهارشنبه 13 مرداد 1395, 01:10 صبح
در مورد نکته دوم شاید دقیق منظورش رو نگرفته باشم اما دلایلی هست که چرا در کانستراکتور یک متد دیگه رو فراخوانی نکنیم.
نکته اول اینکه توجه داشته باشید هنگام ساختن یک آبجکت از SubClass، ابتدا کانستراکتور SuperClass صدا زده خواهد شد. برای همین منظور توصیه میشه در کانستراکتور subclass همیشه قبل از هر چیزی یک super(...) بنویسیم ( سه نقطه بسته به پارامترهای کانستراکتور superclass). اگر شما ننویسید خود کامپایلر به صورت پیشفرض اینکار رو انجام خواهد داد. همچنین super رو در کانستراکتور فقط در اولین خط میتونید بنویسید.
برای تست این موضوع میتونید یک کانستراکتور در کلاس SuperClass و یک کانستراکتور در کلاس SubClass بنویسید:
class SuperClass { public SuperClass(){
System.out.println("SuperClass Constructor");
}
}
class SubClass extends SuperClass{
public SubClass(){
System.out.println("SubClass Constructor");
}
}
و یک آبجکت new SubClass() بسازید و خروجی رو ببینید.
نکته دوم: اگر شما در SuperClass یک متد رو صدا بزنید:
class SuperClass { public SuperClass(){
xMethod();
}
}
و یک آبجکت از subclass بسازید، با اینکه منظور شما عمل چاپ SuperClass xMethod بوده اما در این مورد کانستراکتور SuperClass متد xMethod کلاس SubClass رو صدا می زنه. و اگر متد SubClass.xMethod این باشه:
public void xMethod(){ System.out.println("SubClass xMethod");
}
عمل چاپ SubClass xMethod انجام میشه (یا در مثال پست قبل SubClass xMethod و SuperClass xMethod ). در نتیجه عملی انجام میشه که خلاف چیزی بوده که superclass میخواسته انجام بده.
در نتیجه call کردن یک متد در کانستراکتور superclass و همچنین امکان override کردن اون متد در subclass باعث میشه اجرای کانستراکتور superclass متد subclass رو صدا بزنه. و این خودش میتونه مشکلاتی رو به همراه داشته باشه.
اما متدهای استاتیک این مشکل رو ندارن چون نیازی به ساخت آبجکت نیست و در نتیجه کانستراکتور صدا زده نمیشه.
vahid-p
چهارشنبه 13 مرداد 1395, 01:41 صبح
در خصوص پست دوم بد نیست بدونید دلیل اینکه چرا کانستراکتور superclass هنگام ساختن آبجکت برای subclass متد override شده subclass رو صدا میزنه و نه متد خودش رو. با یک مثال براتون توضیح میدم:
میدونید که داخل یک کلاس ما به کلاس بالاتر (superclass) دسترسی داریم اما به کلاس پایینتر (subclass) دسترسی نداریم چون اصولا نمیدونیم subclass ای در آینده از کلاس فعلی مشتق خواهد شد یا نه. در نتیجه دسترسی ها در درخت ارث بری از پایین به بالاتر است. خب اگر ما کلاسی داشته باشیم که متدی داشته باشه به اسم paintBackground و در کانستراکتور این کلاس این متد فراخوانی بشه و این متد پس زمینه رو "قرمز" کنه، و بعد یک subclass داشته باشیم که متد paintBackground رو override کنه و بگه پس زمینه رو "آبی" کن، اونوقت کانستراکتور superclass دقیقا منظورش کدوم بوده؟ نمیتونه بگه منظورم متد کلاس خودم بوده یا کلاس پایینتر. چون نمیتونه کلاس پایینتر رو مشخص کنه و بین این دو تمایز قائل بشه. و منظور از override هم یعنی من میخوام این متد جای متد قبلی قرار بگیره، و superclass بین این دو نمیتونه انتخاب کنه.
هر چند متد ها هم در این قاعده مثل کانستراکتور هستند، اما فراخوانی متدهای superclass اختیاری است (و میتونید هر کدوم لازمه رو override کنید و داخلش از super استفاده کنید یا خیر) اما فراخوانی کانستراکتور superclass اجباری!
-------------------------------------------------------------------------------------------------------------
فکر کنم منظور این نکته داخل عکس قسمت دوم چیزی نبود که در پست دومم گفتم (هر چند مفهومی که گفتم دونستنش خالی از لطف نیست)، اما شاید منظورش اینه که:
یک متد چه استاتیک چه غیر استاتیک میتونن از کلاس خودشون شی بسازن (در نتیجه کانستراکتور فراخوانی میشه) ولی داخل یک کانستراکتور نمیتونی متد استاتیک رو فراخوانی کنی ولی متد غیراستاتیک رو میشه فراخوانی کرد. در نتیجه اگر متد استاتیک باشه و شی بسازی دور (حلقه بینهایت) ایجاد نمیشه ولی برای متد غیراستاتیک این دور میتونه ایجاد بشه و یک ساب کلاس ممکنه بدون اطلاع از سوپر کلاس این دور رو ایجاد کنه.
اینم دلیل دوم
یونس ابراهیمی
چهارشنبه 13 مرداد 1395, 10:54 صبح
اینم یه مثال تکمیلی خدمت شما
فرض کنید شما متد A را در کلاس A دارید و کلاس B از کلاس A ارث بری می کند، در این صورت متد A در کلاس B در دسترس خواهد بود. اما متد A دقیق همان متدی است که از کلاس A به ارث برده شده است. حال اگر بخواهید که این متد رفتار متفاوتی از خود نشان دهد چکار می کنید؟ برای حل این مشکل باید متد کلاس پایه را Override کنید. به تکه کد زیر توجه کنید:
package myfirstprogram;
class Parent
{
public void ShowMessage()
{
System.out.println("Message from Parent.");
}
}
class Child extends Parent
{
public void ShowMessage()
{
System.out.println("Message from Child.");
}
}
public class MyFirstProgram
{
public static void main(String[] args)
{
Parent myParent = new Parent();
Child myChild = new Child();
myParent.ShowMessage();
myChild.ShowMessage();
}
}
همانطور که در کد بالا مشاهده می کنید دو کلاس یه نام Parent (خطوط 9-3) و Child (خطوط 17-11) تعریف کرده ایم. کلاس Child که از کلاس Parent ارث می برد شامل متدی است که متد ()ShowMessage از کلاس پایه را override یا به صورت دیگری پیاده سازی می کند. همانطور که مشاهده می کنید این دو متد دقیقا شبیه به هم هستند و تنها اختلاف آنها در پیامی است که نشان می دهند. برای Override کردن یک متد قواعدی وجود دارد که در زیر به آنها اشاره شده است :
تابع override شده یکی باشد.
نوع مقدار بازگشتی تابع باید همانند یا فرزندی از نوع مقدار بازگشتی تابع override شده کلاس پدر باشد.
سطح دسترسی تابع نمی تواند محدودتر از سطح دسترسی تابع override شده باشد. برای مثال: اگر تابع کلاس پدر به صورت public تعریف شده باشد، در این صورت تابع کلاس فرزند نمی تواند private یا protected باشد.
تنها توابعی از کلاس پدر که توسط کلاس فرزند ارث بری شده اند می توانند override شوند.
توابع static نمی توانند override شوند، ولی می توانند دوباره در کلاس فرزند تعریف شوند.
اگر تابعی نمی تواند ارث برده شود، همانطور هم نمی تواند override شود.
کلاس فرزند موجود در پکیج یکسان با کلاس پدر، می تواند تمامی توابعی از کلاس پدر را که به صورت private یا final تعریف نشده باشند را override کند.
کلاس فرزند در یک پکیج دیگر از کلاس پدر تنها می تواند توابع public یا protected کلاس پدر را که final نیستند را override کند.
سازنده ها نمی توانند override شوند.
با استفاده از کلمه کلیدی super (خط 15) می توانید متد کلاس پایه را در داخل متد override شده فراخوانی کنید:
package myfirstprogram;
class Parent
{
public void ShowMessage()
{
System.out.println("Message from Parent.");
}
}
class Child extends Parent
{
public void ShowMessage()
{
super.ShowMessage();
System.out.println("Message from Child.");
}
}
public class MyFirstProgram
{
public static void main(String[] args)
{
Parent myParent = new Parent();
Child myChild = new Child();
myParent.ShowMessage();
myChild.ShowMessage();
}
}
می توان یک کلاس دیگر که از کلاس Child ارث بری می کند ایجاد کرده و دوباره متد ShowMessage() را override کرده و آنرا به صورت دیگر پیاده سازی کنیم. اگر بخواهید متدی را که ایجاد کرده اید به وسیله سایر کلاسها override نشود کافیست که از کلمه کلیدی final به صورت زیر استفاده کنید :
public final void ShowMessage()
حال اگر کلاس دیگری از کلاس Child ارث ببرد نمی تواند متد ShowMessage() را override کند.
منبع : w3-farsi.com (http://www.w3-farsi.com)
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.