دستگرمی پانزدهم
اینبار یک دستگرمی با چاشنی وراثت داریم! این دستگرمی رو جناب آقای ابوالفضل صادقی تهیه کردند.
با توجه به اینکه متد printf مانند printf در سی عمل میکند و به جای s% رشته و به جای d% مقدار int را جایگزین میکند، خروجی کد زیر را از بین گزینههای زیر انتخاب کنید.
public class Main { public static void main(String[] args) { new Child(); System.out.println("STATIC FIELD AGE IS " + Child.age); } } class Parent { public static int age = 48; public final String name = "ahmed"; public String family = "ahmedi"; private String phone = "+981212121212"; public Parent() { System.out.println("=======running on========>" + this.getClass()); System.out.printf("constructor$name:%s\n", name); logName(); System.out.printf("constructor$family:%s\n", family); logFamily(); System.out.printf("constructor$age:%d\n", age); logAge(); System.out.printf("constructor$phone:%s\n", phone); logPhone(); } public void logName() { System.out.printf("name is %s\n",this.name); } public void logFamily() { System.out.printf("family is %s\n", this.family); } public void logAge() { System.out.printf("age is %d\n", this.age); } private void logPhone() { System.out.printf("phone is %s\n", this.phone); } } class Child extends Parent { public String name = "jafari"; public Child() { System.out.println("=======parent is=========>" + super.getClass()); System.out.println("=======running on========>" + this.getClass()); System.out.printf("constructor$name:%s\n", name); logName(); System.out.printf("constructor$family:%s\n", family); logFamily(); System.out.printf("constructor$age:%d\n", age); logAge(); } @Override public void logFamily() { System.out.println("family is akbarAbadi"); } }
گزینهها
گزینه ۱
=======running on========>class Child constructor$name:ahmed name is ahmed constructor$family:ahmedi family is akbarAbadi constructor$age:48 age is 48 constructor$phone:+981212121212 phone is +981212121212 =======parent is=========>class Child =======running on========>class Child constructor$name:jafari name is ahmed constructor$family:ahmedi family is akbarAbadi constructor$age:48 age is 48 STATIC FIELD AGE IS 48
گزینه ۲
=======running on========>class Parent constructor$name:ahmed name is ahmed constructor$family:ahmedi family is ahmedi constructor$age:48 age is 48 constructor$phone:+981212121212 phone is +981212121212 =======parent is=========>class Parent =======running on========>class Child constructor$name:jafari name is jafari constructor$family:ahmedi family is akbarAbadi constructor$age:48 age is 48 STATIC FIELD AGE IS 48
گزینه ۳
=======running on========>class Child constructor$name:jafari name is jafari constructor$family:ahmedi family is ahmedi constructor$age:48 age is 48 constructor$phone:+981212121212 phone is +981212121212 =======parent is=========>class Parent =======running on========>class Child constructor$name:jafari name is jafari constructor$family:ahmedi family is akbarAbadi constructor$age:48 age is 48 STATIC FIELD AGE IS 0
گزینه ۴
=======running on========>class Parent constructor$name:jafari name is jafari constructor$family:ahmedi family is ahmedi constructor$age:48 age is 48 constructor$phone:+981212121212 phone is +981212121212 =======parent is=========>class Parent =======running on========>class Child constructor$name:jafari name is jafari constructor$family:ahmedi family is akbarAbadi constructor$age:48 age is 48 STATIC FIELD AGE IS 0
طراح عزیز: جناب آقای ابوالفضل صادقی
پاسخ صحیح: گزینه شماره ۱
توضیح در مورد این پاسخ را در قالب چند نکته با هم میبینیم:
-
نکته ۱: وقتی یک کلاس را می سازید ابتدا constructor والد فراخوانی می شود. اگر در خط اول سازندهی فرزند، سازنده پدر فراخوانی نشود، کامپایلر جاوا به شکل ضمنی سازندهی والد را با super() فراخوانی می کند. پس ابتدا سازنده پدر تفسیر میکنیم.
-
نکته ۲: نکته حیرت انگیز اینکه بخاطر اینکه ما کلاس فرزند را ساختهایم و سازنده پدر هم فراخوانی شده دلیل بر این نیست که this شیای از کلاس پدر باشد! در حقیقت در اینجا this.getClass() مشخص میکند this از نوع کلاس فرزند است. (گزینه ۲ و ۴ حذف میشوند.)
-
نکته ۳: هرچند که ما متغیر name را در کلاس فرزند دوباره تعریف کردهایم، آن هم با یک مقدار دیگر ولی این کار هیچ تاثیری در کلاس والد ندارد. (توجه کنید که هیچ عیبی ندارد که به متغیر final دوباره مقدار دادهایم! دلیلش را در دستگرمی ۱۶ بررسی میکنیم.)
-
نکته ۴: اگر متدی که در کلاس فرزند override شده، در سازنده والد فراخوانی شود، سازنده والد از متد override شده استفاده می کنه و نه مال خودش! (در این مورد بیشتر در دستگرمی بیشتر صحبت میکنیم.)
باقی نکات مربوط به خود سازنده فرزند میشود. (دستورات بعد از super)
-
نکته ۵: هرچند super به والد اشاره دارد (مثلا اگر بنویسیم super() سازنده پدر فراخوانی میشود یا اینکه super.someVar مقدار یک متغیر از کلاس پدر را بر می گرداند و super.someMethod() متدی از پدر رو فراخوانی می کنه هرچند که override شده باشند) ولی super.getClass() میگوید super از نوع کلاس فرزند است.
-
نکته ۶: متغیر name در کلاس فرزند دوباره تعریف شده و مقدار متفاوتی گرفتهاست، سازنده فرزند از name بازتعریفشده استفاده می کند ولی چون متد logName در فرزند override نشده است، تعریف دوباره name تاثیری در عملکرد logName ندارد و همان مقدار کلاس والد چاپ میشود.
-
نکته ۷: از اینجا به بعد همانطور که میدانیم اولویت با متدهای override شده است.
-
نکته ۸: در متد main بعد از اتمام عملیات new مقدار متغیر age از کلاس فرزند فراخوانی شده است. میدانیم که age عضو static در کلاس والد است. توجه کنیم که عضو های static هم امکان استفاده توسط توسط فرزند را دارند پس نتیجه چاپ همان ۴۸ خواهد بود.
-
نکته ۹: به عنوان نکته آخر توجه داشته باشید که اگر در کلاس والد حتی اگه this.logName فراخوانی شود (به هدف صدا شدن متد logName والد) باز هم logName فرزند صدا زده میشود.
.
.
.
.
با ما همراه باشید
آدرس کانال تلگرام: JavaCupIR@
آدرس اکانت توییتر: JavaCupIR@
آدرس صفحه اینستاگرام: javacup.ir
صفحه ویرگول: javcup
آدرس گروه لینکدین: Iranian Java Developers