قد لا يكون الكثير من الأشخاص على دراية بفئات Java الداخلية، وفي الواقع، يوجد مفهوم مماثل في لغة C++، وهو أن الاختلافات والاتصالات بين الاثنين ستتم مقارنتها أدناه. ظاهريًا، الطبقة الداخلية هي مجرد فئة أخرى محددة داخل الفصل (كما سترى أدناه، يمكن تعريف الفئات الداخلية في العديد من الأماكن)، ولكن في الواقع الأمر ليس بهذه البساطة للوهلة الأولى، تبدو الطبقات الداخلية قليلاً قد لا تكون الفائدة واضحة جدًا للمبتدئين، ولكن مع فهم أعمق لها، ستجد أن مصممي Java لديهم نوايا حسنة في الفئات الداخلية. يعد تعلم استخدام الفئات الداخلية جزءًا من إتقان برمجة Java المتقدمة، مما يسمح لك بتصميم بنية برنامجك بشكل أكثر أناقة. ولنتعرف عليه من الجوانب التالية:
الاجتماع الأول
انسخ رمز الكود كما يلي:
محتويات الواجهة العامة {
قيمة كثافة العمليات ()؛
}
وجهة الواجهة العامة {
سلسلة قراءة التسمية ()؛
}
سلع الطبقة العامة {
محتوى الطبقة الخاصة ينفذ المحتويات {
كثافة العمليات الخاصة ط = 11؛
قيمة كثافة العمليات العامة () {
العودة أنا؛
}
}
فئة محمية GDestination تنفذ الوجهة {
تسمية سلسلة خاصة؛
GDestination الخاص (سلسلة إلى أين) {
label = WhereTo;
}
سلسلة عامة readLabel () {
تسمية العودة؛
}
}
الوجهة العامة dest(سلسلة ق) {
إرجاع الوجهة (الوجهات) الجديدة ؛
}
المحتويات العامة تابع () {
إرجاع محتوى جديد ()؛
}
}
فئة السلع الاختبارية {
public static void main(String[] args) {
البضائع ع = البضائع الجديدة ()؛
المحتويات ج = p.cont();
الوجهة d = p.dest("بكين");
}
}
في هذا المثال، يتم تعريف فئات المحتوى وGDestination داخل فئة البضائع، ولها معدلات محمية وخاصة على التوالي للتحكم في مستويات الوصول. يمثل المحتوى محتوى البضائع، وتمثل GDestination وجهة البضائع. يقومون بتنفيذ واجهتين للمحتوى والوجهة على التوالي. في الطريقة الرئيسية التالية، يمكنك استخدام Contents c وDestination d مباشرة للعمل، ولا ترى حتى أسماء هاتين الفئتين الداخليتين! بهذه الطريقة، فإن الفائدة الأولى من الفئات الداخلية هي إخفاء العمليات التي لا تريد أن يعرفها الآخرون، أي التغليف.
وفي الوقت نفسه، اكتشفنا أيضًا الطريقة الأولى للحصول على كائن فئة داخلية خارج نطاق الفئة الخارجية، وهي إنشائه وإعادته باستخدام أساليب فئته الخارجية. تقوم الطرق cont() و dest() في المثال أعلاه بذلك. فهل هناك أي طريقة أخرى؟
بالطبع يوجد،
صيغة الجملة هي كما يلي:
ExternalObject=new ExternalClass(Constructor Parameters);
ExternalClass.innerClass insideObject=outerObject.new InnerClass(معلمات المُنشئ);
لاحظ أنه عند إنشاء كائن فئة داخلية غير ثابت، يجب عليك أولاً إنشاء كائن فئة خارجية مطابق. أما بالنسبة للسبب، فهذا يقودنا إلى موضوعنا التالي. كائنات الطبقة الداخلية غير الثابتة لها إشارات إلى كائنات الطبقة الخارجية الخاصة بها،
قم بتعديل المثال السابق قليلاً:
انسخ رمز الكود كما يلي:
سلع الطبقة العامة {
معدل قيمة int الخاص = 2 ؛
محتوى الطبقة الخاصة ينفذ المحتويات {
Private int i = 11 * valueRate;
قيمة كثافة العمليات العامة () {
العودة أنا؛
}
}
فئة محمية GDestination تنفذ الوجهة {
تسمية سلسلة خاصة؛
GDestination الخاص (سلسلة إلى أين) {
label = WhereTo;
}
سلسلة عامة readLabel () {
تسمية العودة؛
}
}
الوجهة العامة dest(سلسلة ق) {
إرجاع الوجهة (الوجهات) الجديدة ؛
}
المحتويات العامة تابع () {
إرجاع محتوى جديد ()؛
}
}
نقوم هنا بإضافة قيمة متغير عضو خاص إلى فئة البضائع، مما يعني أن معامل قيمة البضائع يتم ضربه به عندما تقوم طريقة value() الخاصة بمحتوى الفئة الداخلية بحساب القيمة. وجدنا أن value() يمكنها الوصول إلى valueRate، وهي الميزة الثانية للفئات الداخلية. يمكن لكائن الفئة الداخلية الوصول إلى محتويات كائن الفئة الخارجية الذي أنشأه، حتى المتغيرات الخاصة! هذه ميزة مفيدة جدًا توفر لنا المزيد من الأفكار والاختصارات عند التصميم. لتحقيق هذه الوظيفة، يجب أن يكون لكائن الفئة الداخلية مرجع لكائن الفئة الخارجية. عندما يقوم مترجم Java بإنشاء كائن فئة داخلية، فإنه يقوم ضمنيًا بتمرير المرجع إلى كائن الفئة الخارجية الخاص به ويحتفظ به. يسمح هذا لكائن الفئة الداخلية بالوصول دائمًا إلى كائن الفئة الخارجية، ولهذا السبب أيضًا، لإنشاء كائن فئة داخلية خارج نطاق الفئة الخارجية، يجب عليك أولاً إنشاء كائن الفئة الخارجية الخاص به.
قد يتساءل بعض الناس، ماذا علي أن أفعل إذا كان متغير العضو في الفئة الداخلية له نفس اسم متغير العضو في الفئة الخارجية، أي أن متغير العضو في الفئة الخارجية الذي يحمل نفس الاسم محظور؟ لا بأس، تستخدم Java التنسيق التالي للتعبير عن المراجع للفئات الخارجية:
outerClass.this
مع ذلك، نحن لا نخاف من هذا الوضع التدريعي.
الطبقة الداخلية الساكنة
مثل الطبقات العادية، يمكن أن تكون الطبقات الداخلية أيضًا ثابتة. ومع ذلك، بالمقارنة مع الفئات الداخلية غير الثابتة، فإن الفرق هو أن الفئات الداخلية الثابتة ليس لها مراجع خارجية. هذا في الواقع مشابه جدًا للفئات المتداخلة في C++، والفرق الأكبر بين فئات Java الداخلية والفئات المتداخلة في C++ هو ما إذا كانت هناك مراجع خارجية، بالطبع، من منظور التصميم وبعض تفاصيله، هناك فرق.
بالإضافة إلى ذلك، في أي فئة داخلية غير ثابتة، لا يمكن أن تكون هناك بيانات ثابتة أو أساليب ثابتة أو فئة داخلية ثابتة أخرى (يمكن أن تتداخل الفئات الداخلية في أكثر من مستوى واحد). ولكن يمكنك الحصول على كل هذا في الطبقات الداخلية الثابتة. ويمكن اعتبار هذا الفرق الثاني بين الاثنين.
الطبقة الداخلية المحلية
نعم، يمكن أيضًا أن تكون فئات Java الداخلية محلية، ويمكن تعريفها ضمن طريقة أو حتى كتلة تعليمات برمجية.
انسخ رمز الكود كما يلي:
سلع الطبقة العامة 1 {
الوجهة العامة dest(سلسلة ق) {
فئة GDestination تنفذ الوجهة {
تسمية سلسلة خاصة؛
GDestination الخاص (سلسلة إلى أين) {
label = WhereTo;
}
سلسلة عامة readLabel () {
تسمية العودة؛
}
}
إرجاع الوجهة (الوجهات) الجديدة ؛
}
public static void main(String[] args) {
Goods1 g = new Goods1();
الوجهة d = g.dest("بكين");
}
}
ما ورد أعلاه هو أحد الأمثلة على ذلك. في الطريقة dest، نحدد فئة داخلية، وأخيرًا تقوم هذه الطريقة بإرجاع كائن هذه الفئة الداخلية. إذا كنا نحتاج فقط إلى إنشاء كائن من فئة داخلية وإنشائه في الخارج، فيمكننا القيام بذلك. بالطبع، يمكن للفئات الداخلية المحددة بالطرق تنويع التصميم، ولا تقتصر استخداماتها على هذا.
إليك مثالًا أكثر غرابة:
انسخ رمز الكود كما يلي:
سلع الطبقة العامة 2 {
تتبع داخلي باطل خاص (منطقي ب) {
إذا (ب) {
قسيمة تتبع الفئة {
معرف السلسلة الخاصة؛
تتبع قسيمة (سلسلة ق) {
معرف = الصورة؛
}
سلسلة getSlip () {
معرف العودة؛
}
}
TrackingSlip ts = new TrackingSlip("slip");
String s = ts.getSlip();
}
}
مسار الفراغ العام () {
InternalTracking(true);
}
public static void main(String[] args) {
Goods2 g = new Goods2();
g.track();
}
}
لا يمكنك إنشاء كائن من هذه الفئة الداخلية خارج نطاق if، لأنه يتجاوز نطاقه. ومع ذلك، أثناء التجميع، يتم تجميع الفئة الداخلية TrackingSlip في نفس الوقت مع الفئات الأخرى، باستثناء أن لها نطاقًا خاصًا بها وهي غير صالحة خارج هذا النطاق. وبخلاف ذلك، فهي لا تختلف عن الفئات الداخلية الأخرى.
الطبقة الداخلية المجهولة
قد تبدو قواعد بناء الجملة الخاصة بالفئات الداخلية المجهولة في Java غريبة بعض الشيء، ولكن مثل المصفوفات المجهولة، عندما تحتاج فقط إلى إنشاء كائن من فئة ولا تحتاج إلى اسمه، فإن استخدام الفئات الداخلية يمكن أن يجعل التعليمات البرمجية تبدو موجزة وواضحة. قواعد بناء الجملة الخاصة بها هي كما يلي:
اسم الواجهة الجديدة () {......} أو اسم الطبقة الفائقة الجديدة () {......}؛
لنواصل مع المثال أدناه:
انسخ رمز الكود كما يلي:
سلع الطبقة العامة3 {
المحتويات العامة تابع () {
إرجاع محتويات جديدة () {
كثافة العمليات الخاصة ط = 11؛
قيمة كثافة العمليات العامة () {
العودة أنا؛
}
};
}
}
تستخدم الطريقة cont() هنا فئة داخلية مجهولة لإرجاع كائن من فئة ينفذ واجهة المحتويات مباشرة، والذي يبدو بسيطًا جدًا بالفعل.
في المحولات المجهولة لمعالجة أحداث Java، يتم استخدام الفئات الداخلية المجهولة على نطاق واسع. على سبيل المثال، عندما تريد إغلاق النافذة، أضف هذا الكود:
انسخ رمز الكود كما يلي:
frame.addWindowListener(new WindowAdapter(){
نافذة فارغة عامة (WindowEvent e) {
System.exit(0);
}
});
شيء واحد يجب ملاحظته هو أنه نظرًا لأن الفئة الداخلية المجهولة ليس لها اسم، فلا يوجد بها مُنشئ (ولكن إذا ورثت الفئة الداخلية المجهولة فئة أصل تحتوي فقط على مُنشئ ذي معلمات، فيجب إحضار هذه المعلمات عند إنشائها، واستخدام السوبر الكلمة الأساسية لاستدعاء المحتوى المقابل أثناء عملية التنفيذ). إذا كنت تريد تهيئة متغيرات أعضائها، فهناك عدة طرق:
إذا كان موجودًا في فئة داخلية مجهولة لطريقة ما، فيمكنك استخدام هذه الطريقة لتمرير المعلمات التي تريدها، ولكن تذكر أنه يجب إعلان هذه المعلمات نهائية.
قم بتحويل الفئة الداخلية المجهولة إلى فئة داخلية محلية مسماة بحيث يمكن أن تحتوي على مُنشئ.
استخدم كتلة التهيئة في هذه الفئة الداخلية المجهولة.
لماذا تحتاج الطبقات الداخلية؟
ما هي فوائد الطبقات الداخلية جافا؟ لماذا تحتاج الطبقات الداخلية؟
أولاً، لنأخذ مثالاً بسيطًا إذا كنت ترغب في تنفيذ واجهة، ولكن الطريقة في هذه الواجهة لها نفس الاسم والمعلمات مثل الطريقة في الفصل الذي صممته، فماذا يجب عليك فعله؟ في هذا الوقت، يمكنك إنشاء فئة داخلية لتنفيذ هذه الواجهة. نظرًا لأن الطبقة الداخلية يمكن الوصول إليها من قبل كل شيء في الطبقة الخارجية، فإن القيام بذلك سيؤدي إلى إنجاز جميع الوظائف التي قد تكون لديك إذا قمت بتنفيذ الواجهة مباشرة.
لكن قد ترغب في التساؤل، ألا يكفي مجرد تغيير الطريقة؟
في الواقع، استخدام هذا كسبب لتصميم الطبقات الداخلية أمر غير مقنع حقًا.
السبب الحقيقي هو أن الفئات والواجهات الداخلية في Java معًا يمكنها حل المشكلة التي غالبًا ما يشتكي منها مبرمجو C ++ في Java دون وراثة متعددة. في الواقع، يعد تصميم الميراث المتعدد لـ C++ معقدًا للغاية، ويمكن لـ Java تحقيق تأثير الميراث المتعدد بشكل جيد للغاية من خلال الفئات والواجهات الداخلية.