ہائے! آج ہم ایک اہم طریقہ کار دیکھیں گے: نیسٹڈ کلاسز میں وراثت۔ کیا آپ نے کبھی اس بارے میں سوچا ہے کہ اگر آپ کو نیسٹڈ کلاس کو کسی اور کلاس کا وارث بنانے کی ضرورت ہو تو آپ کیا کریں گے۔ اگر نہیں، تو مجھ پر یقین کریں: یہ صورت حال مبہم ہوسکتی ہے، کیونکہ بہت ساری باریکیاں ہیں۔
- کیا ہم ایک نیسٹڈ کلاس کو کسی کلاس کا وارث بنا رہے ہیں؟ یا ہم کسی کلاس کو نیسٹڈ کلاس کا وارث بنا رہے ہیں؟
- کیا بچہ/والدین طبقہ ایک عام عوامی طبقہ ہے، یا یہ بھی ایک نیسٹڈ کلاس ہے؟
- آخر میں، ان تمام حالات میں ہم کس قسم کی نیسٹڈ کلاسز استعمال کرتے ہیں؟
جامد نیسٹڈ کلاسز
ان کے وراثت کے اصول سب سے آسان ہیں۔ یہاں آپ تقریباً ہر وہ کام کر سکتے ہیں جو آپ کا دل چاہے۔ ایک جامد نیسٹڈ کلاس وراثت میں مل سکتی ہے:- ایک عام کلاس
- ایک جامد نیسٹڈ کلاس جس کا اعلان بیرونی طبقے یا اس کے آباؤ اجداد میں کیا جاتا ہے۔
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
آئیے کوڈ کو تبدیل کرنے کی کوشش کریں اور ایک Drawing
جامد نیسٹڈ کلاس بنائیں اور اس کی اولاد — Boeing737Drawing
۔
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
public static class Boeing737Drawing extends Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
جیسا کہ آپ دیکھ سکتے ہیں، کوئی مسئلہ نہیں. یہاں تک کہ ہم کلاس کو نکال سکتے ہیں Drawing
اور اسے جامد نیسٹڈ کلاس کے بجائے ایک عام عوامی کلاس بنا سکتے ہیں — کچھ نہیں بدلے گا۔
public class Drawing {
}
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Boeing737Drawing extends Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
ہم یہ سمجھتے ہیں۔ لیکن کون سی کلاسیں جامد نیسٹڈ کلاس کا وارث ہوسکتی ہیں؟ عملی طور پر کوئی بھی! Nested/non-nested، static/non-static — اس سے کوئی فرق نہیں پڑتا۔ یہاں ہم Boeing737Drawing
اندرونی کلاس کو جامد نیسٹڈ کلاس کا وارث بناتے ہیں Drawing
:
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
public class Boeing737Drawing extends Drawing {
public int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
آپ اس طرح کی ایک مثال بنا سکتے ہیں Boeing737Drawing
:
public class Main {
public static void main(String[] args) {
Boeing737 boeing737 = new Boeing737(1990);
Boeing737.Boeing737Drawing drawing = boeing737.new Boeing737Drawing();
System.out.println(drawing.getMaxPassengersCount());
}
}
اگرچہ ہماری Boeing737Drawing
کلاس کو ایک جامد کلاس وراثت میں ملتی ہے، لیکن یہ خود جامد نہیں ہے! نتیجے کے طور پر، اسے ہمیشہ بیرونی طبقے کی مثال کی ضرورت ہوگی۔ ہم Boeing737Drawing
کلاس کو کلاس سے نکال Boeing737
کر ایک سادہ پبلک کلاس بنا سکتے ہیں۔ کچھ نہیں بدلتا۔ یہ اب بھی Drawing
جامد نیسٹڈ کلاس کا وارث ہوسکتا ہے۔
public class Boeing737 {
private int manufactureYear;
public static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
}
public class Boeing737Drawing extends Boeing737.Drawing {
public int getMaxPassengersCount() {
return Boeing737.maxPassengersCount;
}
صرف اہم نکتہ یہ ہے کہ اس معاملے میں ہمیں جامد maxPassengersCount
متغیر کو پبلک کرنے کی ضرورت ہے۔ اگر یہ نجی رہتا ہے، تو ایک عام عوامی طبقے کو اس تک رسائی حاصل نہیں ہوگی۔ ہم نے جامد کلاسوں کا پتہ لگا لیا ہے! :) اب چلتے ہیں اندرونی کلاسز کی طرف۔ وہ 3 اقسام میں آتے ہیں: سادہ اندرونی کلاسز، لوکل کلاسز، اور گمنام اندرونی کلاسز۔ ایک بار پھر، آئیے سادہ سے پیچیدہ کی طرف چلتے ہیں :)
گمنام اندرونی کلاسز
ایک گمنام اندرونی طبقہ دوسری کلاس کا وارث نہیں ہو سکتا۔ کوئی دوسرا طبقہ گمنام طبقے کا وارث نہیں ہو سکتا۔ یہ کوئی آسان نہیں ہو سکتا! :)مقامی کلاسز
مقامی کلاسز (اگر آپ بھول گئے ہیں) کسی اور کلاس کے کوڈ بلاک کے اندر اعلان کیا جاتا ہے۔ اکثر، یہ بیرونی طبقے کے کسی نہ کسی طریقے کے اندر ہوتا ہے۔ منطقی طور پر، اسی طریقہ (یا کوڈ بلاک) کے اندر صرف دوسری مقامی کلاسیں ہی مقامی کلاس کا وارث بن سکتی ہیں۔ یہاں ایک مثال ہے:public class PhoneNumberValidator {
public void validatePhoneNumber(final String number) {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber() {
this.phoneNumber = number;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
class CellPhoneNumber extends PhoneNumber {
}
class LandlinePhoneNumber extends PhoneNumber {
}
// ...number validation code
}
}
یہ مقامی کلاسوں پر ہمارے سبق کا کوڈ ہے۔ ہمارے نمبر کی تصدیق کرنے والی کلاس میں ایک PhoneNumber
مقامی کلاس ہے۔ اگر ہمیں دو الگ الگ اداروں کی نمائندگی کرنے کی ضرورت ہے، مثال کے طور پر، ایک موبائل فون نمبر اور ایک لینڈ لائن فون نمبر، تو ہم یہ صرف اسی طریقہ کے اندر کر سکتے ہیں۔ وجہ سادہ ہے: مقامی کلاس کا دائرہ کار اس طریقہ (کوڈ بلاک) تک محدود ہے جہاں اسے اعلان کیا جاتا ہے۔ نتیجے کے طور پر، ہم اسے بیرونی طور پر استعمال نہیں کر پائیں گے (بشمول طبقاتی وراثت کے لیے)۔ تاہم، خود مقامی طبقے کے اندر وراثت کے امکانات بہت وسیع ہیں! ایک مقامی کلاس وراثت میں مل سکتی ہے:
- ایک عام طبقہ۔
- ایک اندرونی طبقہ جو مقامی طبقے کے طور پر یا اس کے آباؤ اجداد میں سے کسی ایک میں قرار دیا جاتا ہے۔
- اسی طریقہ (کوڈ بلاک) میں اعلان کردہ ایک اور مقامی کلاس۔
public class PhoneNumberValidator {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
public void validatePhoneNumber(final String number) {
class CellPhoneNumber extends PhoneNumber {
public CellPhoneNumber(String phoneNumber) {
super(number);
}
}
class LandlinePhoneNumber extends PhoneNumber {
public LandlinePhoneNumber(String phoneNumber) {
super(number);
}
}
// ...number validation code
}
}
یہاں ہم نے PhoneNumber
کلاس کو طریقہ سے ہٹا دیا validatePhoneNumber()
اور اسے مقامی کلاس کی بجائے اندرونی کلاس بنا دیا۔ یہ ہمیں اپنی 2 مقامی کلاسوں کو اس کا وارث بنانے سے نہیں روکتا۔ مثال 2 — "... یا اس طبقے کے آباؤ اجداد میں۔" اب یہ پہلے سے زیادہ دلچسپ ہے. ہم PhoneNumber
وراثت کے سلسلے میں اور بھی اوپر جا سکتے ہیں۔ آئیے ایک تجریدی AbstractPhoneNumberValidator
کلاس کا اعلان کرتے ہیں، جو ہماری PhoneNumberValidator
کلاس کا آباؤ اجداد بن جائے گا:
public abstract class AbstractPhoneNumberValidator {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
}
جیسا کہ آپ دیکھ سکتے ہیں، ہم نے صرف اس کا اعلان نہیں کیا - ہم نے PhoneNumber
اندرونی طبقے کو بھی اس میں منتقل کیا۔ تاہم، اس کی اولاد میں PhoneNumberValidator
، طریقوں میں اعلان کردہ مقامی کلاسیں PhoneNumber
بغیر کسی مسئلہ کے وراثت میں مل سکتی ہیں!
public class PhoneNumberValidator extends AbstractPhoneNumberValidator {
public void validatePhoneNumber(final String number) {
class CellPhoneNumber extends PhoneNumber {
public CellPhoneNumber(String phoneNumber) {
super(number);
}
}
class LandlinePhoneNumber extends PhoneNumber {
public LandlinePhoneNumber(String phoneNumber) {
super(number);
}
}
// ...number validation code
}
}
وراثت کے رشتے کی وجہ سے، نسلی طبقے کے اندر مقامی طبقات ایک آباؤ اجداد کے اندر کے اندرونی طبقات کو "دیکھتے" ہیں۔ اور آخر میں، چلتے ہیں آخری گروپ کی طرف :)
اندرونی کلاسز
ایک اندرونی طبقہ جس کا اعلان اسی بیرونی طبقے میں کیا گیا ہے (یا اس کی اولاد میں) کسی اور اندرونی طبقے کا وارث ہو سکتا ہے۔ آئیے اندرونی کلاسوں کے اسباق سے سائیکلوں کے ساتھ اپنی مثال کا استعمال کرتے ہوئے اسے دریافت کریں۔public class Bicycle {
private String model;
private int maxWeight;
public Bicycle(String model, int maxWeight) {
this.model = model;
this.maxWeight = maxWeight;
}
public void start() {
System.out.println("Let's go!");
}
class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
class SportSeat extends Seat {
// ...methods
}
}
یہاں ہم نے کلاس Seat
کے اندر اندرونی طبقے کا اعلان کیا Bicycle
۔ ایک خاص قسم کی ریسنگ سیٹ، SportSeat
وراثت میں ملتی ہے۔ لیکن، ہم ایک الگ "ریسنگ بائیسکل" کی قسم بنا سکتے ہیں اور اسے الگ کلاس میں رکھ سکتے ہیں:
public class SportBicycle extends Bicycle {
public SportBicycle(String model, int maxWeight) {
super(model, maxWeight);
}
class SportSeat extends Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
}
یہ بھی ایک آپشن ہے۔ نسل کا اندرونی طبقہ ( SportBicycle.SportSeat
) آباؤ اجداد کے اندرونی طبقوں کو "دیکھتا ہے" اور ان کا وارث بن سکتا ہے۔ اندرونی کلاسوں کو وراثت میں دینا ایک بہت اہم خصوصیت ہے! پچھلی دو مثالوں میں، ہماری SportSeat
کلاس ایک اندرونی کلاس تھی۔ SportSeat
لیکن کیا ہوگا اگر ہم ایک عام عوامی طبقے کو بنانے کا فیصلہ کریں جو بیک وقت Seat
اندرونی طبقے کا وارث ہو؟
// Error! No enclosing instance of type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {
public SportSeat() {
}
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
ہمیں ایک غلطی ہو گئی! کیا آپ اندازہ لگا سکتے ہیں کہ کیوں؟ :) یہ سب سیدھا ہے۔ جب ہم نے Bicycle.Seat
اندرونی طبقے کے بارے میں بات کی، تو ہم نے ذکر کیا کہ بیرونی طبقے کی مثال کا حوالہ واضح طور پر اندرونی طبقے کے کنسٹرکٹر کو دیا جاتا ہے۔ Seat
اس کا مطلب ہے کہ آپ آبجیکٹ بنائے بغیر کوئی چیز نہیں بنا سکتے Bicycle
۔ لیکن ایک کی تخلیق کے بارے میں کیا خیال ہے SportSeat
؟ اس کے برعکس Seat
، اس میں بیرونی طبقے کی مثال کے حوالے سے کنسٹرکٹر کو واضح طور پر منتقل کرنے کا یہ بلٹ ان میکانزم نہیں ہے۔ S تک، کسی Bicycle
شے کے بغیر، ہم کوئی SportSeat
چیز نہیں بنا سکتے، جیسا کہ کے معاملے میں Seat
۔ لہذا، ہمارے لیے صرف ایک ہی کام باقی ہے - واضح طور پر کنسٹرکٹر کو کسی چیز SportSeat
کا حوالہ دیں۔ Bicycle
اسے کرنے کا طریقہ یہاں ہے:
class SportSeat extends Bicycle.Seat {
public SportSeat(Bicycle bicycle) {
bicycle.super();
}
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
ہم ناؤ کا استعمال کرتے ہوئے سپر کلاس کنسٹرکٹر کو کہتے ہیں super();
، اگر ہم کوئی چیز بنانا چاہتے ہیں SportSeat
، تو ہمیں ایسا کرنے سے کوئی نہیں روکے گا:
public class Main {
public static void main(String[] args) {
Bicycle bicycle = new Bicycle("Peugeot", 120);
SportSeat peugeotSportSeat = new SportSeat(bicycle);
}
}
افف! یہ سبق کافی طویل تھا :) لیکن آپ نے بہت کچھ سیکھا! اب یہ کچھ کاموں کو حل کرنے کا وقت ہے! :)
GO TO FULL VERSION