1. rtti:
تتيح لك معلومات نوع وقت التشغيل اكتشاف معلومات النوع واستخدامها أثناء تشغيل البرنامج.
هناك طريقتان لتحديد معلومات حول الكائنات والفئات عند التشغيل في Java: RTTI التقليدية ، والتفكير. دعنا نتحدث عن RTTI.
RTTI: في وقت التشغيل ، حدد نوع الكائن. ولكن يجب أن يكون هذا النوع معروفًا في وقت الترجمة.
دعنا نأخذ مثالاً لرؤية استخدام RTTI. يتضمن ذلك مفهوم الأشكال: السماح للرمز لا يعمل إلا على الإشارات إلى الفئة الأساسية ، وعادة ما ينشئ طرق الاستدعاء في الفئات الفرعية المحددة كائنًا ملموسًا (الدائرة أو المربعة أو المثلث ، انظر المثال أدناه) أدناه)
شكل الفئة التجريدية {// هذا يستدعي طريقة toString () للفئة الحالية ، وإرجاع void المحتوى الفعلي draw () {system.out.println (this + "draw ()") ؛ }. }} class square يمتد الشكل {public string toString () {return "square" ؛ }} Triangle class يمتد الشكل {public string toString () {return "triangle" ؛ }} public static void main (string [] args) {// عند وضع كائن الشكل في صفيف القائمة <Phary> ، سوف يتحول إلى أعلى إلى الشكل ، وبالتالي فقدان قائمة معلومات النوع المحددة <Sape> ShapeList = Arrays.Aslist (New Circle () ، New Square () ، Triangle ()) ؛ // عندما يتم إخراجها من الصفيف ، في الواقع ، يتم الاحتفاظ بجميع عناصر هذه الحاوية ككائنات وستقوم تلقائيًا بتحويل النتيجة إلى الشكل. هذا هو الاستخدام الأساسي لـ RTTI. لـ (شكل الشكل: ShapeList) {lape.draw () ؛ }}نتيجة الإخراج هي:
circledraw () SquareRaw () Triangledraw ()
عند إيداعه في صفيف ، سيتم تحويله تلقائيًا إلى الشكل ، ويتم فقد النوع المحدد. عند إخراجها من المصفوفة ، (تحتفظ حاوية القائمة بكل شيء ككائن) ، فسيقوم تلقائيًا بتحويل النتيجة مرة أخرى إلى الشكل. هذا هو الاستخدام الأساسي لـ RTTI. يتم فحص جميع تحويلات النوع في Java في وقت التشغيل ، أي RTTI: في وقت التشغيل ، حدد نوع الكائن.
التحول أعلاه ليس دقيقًا. عندما يتم إخراج عناصر الصفيف ، يتم تحويل الكائن إلى شكل ، وليس النوع المحدد. يتم ذلك عن طريق الحاويات والأنظمة العامة Java أثناء التجميع ، وهناك عمليات تحويل النوع لضمان ذلك في وقت التشغيل.
يتم تحديد الكود المحدد الذي يمكن تنفيذه في فئة فرعية من خلال كائن الشكل بواسطة تعدد الأشكال. للحصول على التفاصيل ، يعتمد ذلك على الكائن المحدد الذي أشار إليه مرجع الشكل.
بالإضافة إلى ذلك ، باستخدام RTTI ، يمكنك الاستعلام عن النوع الدقيق للكائن المشار إليه بواسطة مرجع الشكل ، ثم تنفيذ طريقة الفئة الفرعية بشكل انتقائي.
2. كائن الفئة:
لفهم كيفية عمل RTTI في Java ، يجب أن تعرف كيفية تمثيل معلومات النوع في وقت التشغيل ، والذي يتم ذلك بواسطة فئة الكائنات الخاصة.
يتم استخدام كائنات الفئة لإنشاء جميع الكائنات "العادية" للفئة. تستخدم Java كائنات الفئة لتنفيذ RTTI.
كلما تم تجميع فئة جديدة ، يتم إنشاء كائن فئة (ملف .class). سيستخدم JVM تشغيل هذا البرنامج النظام الفرعي "Class Loader".
النظام الفرعي لوادر الفئة: يحتوي على سلسلة محمل فئة ، ولكن فقط تحميل فئة أصلي واحد ، وهو جزء من تطبيق JVM. تحميل اللوادر من الدرجة الأصلية فئات موثوقة ، بما في ذلك فصول Java API ، عادة من الأقراص المحلية. عندما تحتاج فئة إلى تحميلها بطريقة معينة لدعم تطبيقات خادم الويب ، يمكن إرفاق لوادر فئة إضافية.
2.1. توقيت تحميل الفصل:
يتم تحميل هذه الفئة عندما ينشئ البرنامج المرجع الأول إلى عضو ثابت في الفصل. هذا يثبت أن المنشئ هو في الواقع طريقة ثابتة للفئة. عند إنشاء كائن جديد من الفصل باستخدام المشغل الجديد ، سيتم أيضًا استخدامه كمرجع للعضو الثابت في الفصل.
يمكن ملاحظة أن برامج Java يتم تحميلها ديناميكيًا وتحميلها عند الطلب. عند الحاجة إلى الفصل ، سيقوم محمل الفئة أولاً بالتحقق مما إذا كان قد تم تحميل كائن الفئة في هذه الفئة. إذا لم يتم تحميله ، فسيجد محمل الفئة الافتراضية ملف .class استنادًا إلى اسم الفئة. التالي هو مرحلة التحقق: عند تحميلها ، يقبلون التحقق للتأكد من أنها غير تالفة ولا تحتوي على رمز Java السيئ.
2.2. الأساليب المتعلقة بالصف ، newinstance ()
فيما يلي مثال لإظهار تحميل كائن الفئة:
الفئة A {// قاعدة رمز ثابت ، يتم تنفيذها عند تحميلها لأول مرة ، ويعرف متى يتم تحميل الفئة عن طريق طباعة معلومات ثابتة {system.out.println ("تحميل A") ؛ }} class b {static {system.out.println ("loading b") ؛ }} class c {static {system.out.println ("loading c") ؛ }} فئة عامة تحميل {public static void main (string [] args) {system.out.println ("تنفيذ main ...") ؛ جديد A () ؛ System.out.println ("بعد جديد A") ؛ حاول {class.forname ("com.itzhai.test.type.b") ؛ } catch (classnotfoundException e) {system.out.println ("Cloud not find Class B") ؛ } system.out.println ("بعد class.forname b") ؛ جديد C () ؛ System.out.println ("بعد New C") ؛ }}نتيجة الإخراج هي:
تنفيذ MAIN ... تحميل AAFTER جديد aloading bafter class.forname bloading cafter جديد ج
يمكن ملاحظة أن كائن الفئة يتم تحميله فقط عند الحاجة. لاحظ طريقة class.forname () هنا:
طريقة forname () هي طريقة للحصول على مرجع إلى كائن الفئة. من خلال الحصول على المرجع المناسب لكائن الفئة ، يمكنك استخدام معلومات النوع في وقت التشغيل.
إذا كان لديك بالفعل كائن اهتمام ، فيمكنك الحصول على مرجع الفصل من خلال اتباع طريقة getClass () التي يوفرها كائن الفئة.
هنا رمز تستخدمه الفصل:
واجهة x {} واجهة y {} واجهة z {} حرف keter {eleft () {} ؛ Letter (int i) {} ؛} class newletter يمتد حروف الحروف x ، y ، z {newletter () {super (1) ؛ ؛ // احصل على اسم الفصل system.out.println ("الاسم البسيط:" + c.getSimplename ()) ؛ // احصل على اسم اسم الفئة المؤهل بالكامل. } public static void main (string [] args) {class c = null ؛ حاول {// الحصول على مرجع الفصل c = class.forname ("com.itzhai.test.type.newletter") ؛ } catch (classnotfoundException e) {system.out.println ("لا يمكن العثور على com.itzhai.test.type.newletter") ؛ System.exit (1) ؛ } // معلومات نوع الواجهة للطباعة (الوجه الفئة: } // الحصول على فئة مرجع فئة فئة Superclass UP = C.GetSuperClass () ؛ كائن obj = null ؛ حاول {// إنشاء مثيل للفئة من خلال طريقة newInstance () obj = up.newinstance () ؛ } catch (instantiationException e) {system.out.println ("لا يمكن إنشاء مثيله") ؛ } catch (alfictalaccessexception e) {system.out.println ("لا يمكن الوصول إلى") ؛ }. }}الإخراج هو:
اسم الفصل: com.itzhai.test.type.x واجهة؟ اسم truesimple: xcanonical الاسم: com.itzhai.test.type.xclass الاسم: com.itzhai.test.type.y واجهة؟ اسم truesimple: ycanonical الاسم: com.itzhai.test.type.yclass الاسم: com.itzhai.test.type.z واجهة؟ اسم truesimple: Zcanonical الاسم: com.itzhai.test.type.zclass الاسم: com.itzhai.test.type.Letter واجهة؟ Falsesimple الاسم: Lettercanonical Name: com.itzhai.test.type.etter
لاحظ أن السلسلة التي تم تمريرها إلى ForName () يجب أن تستخدم اسمًا مؤهلاً بالكامل (بما في ذلك اسم الحزمة).
من خلال الطرق المستخدمة في PrintInfo ، يمكنك اكتشاف بنية الميراث الكاملة للكائن في وقت التشغيل.
باستخدام طريقة NewInstance () من الفئة ، فهي طريقة لتنفيذ "مُنشئ افتراضي" لإنشاء مثيل للفئة. يتم الحصول على مرجع الكائن ، لكنه يشير إلى كائن الحروف عند الرجوع إليه. يجب أن تحتوي الفئات التي تم إنشاؤها باستخدام NewInstance () على مُنشئ افتراضي. (من خلال واجهة برمجة تطبيقات الانعكاس ، يمكنك استخدام أي مُنشئ لإنشاء كائنات فئة ديناميكية).
2.3. الثوابت الحرفية الطبقة:
بالإضافة إلى استخدام طريقة getName () ، توفر Java أيضًا طريقة أخرى لإنشاء مرجع إلى كائن فئة ، أي استخدام الثوابت الحرفية الفئة:
newletter.class ؛
هذه الطريقة بسيطة وآمنة ، ويتم فحصها أثناء التجميع ، مما يجعلها أكثر كفاءة. يمكن استخدامه ليس فقط للفئات العادية ، ولكن أيضًا للواجهات والصفائف وأنواع البيانات الأساسية. بالإضافة إلى ذلك ، بالنسبة لفئة Wrapper لنوع البيانات الأساسية ، هناك أيضًا نوع حقل قياسي. حقل النوع هو مرجع لتنفيذ كائن فئة نوع البيانات الأساسية المقابلة. من أجل التوحيد ، يوصى باستخدام النموذج .class.
2.4. الفرق بين استخدام .class واستخدام طريقة getName () لإنشاء مراجع الكائن:
عند الإنشاء باستخدام .class ، لا يتم تهيئة كائن الفئة تلقائيًا. خطوات الخلق هي كما يلي:
(1) يتم إجراء التحميل بواسطة Loader الفئة: ابحث عن رمز Bytecode (عادة في المسار المحدد بواسطة ClassPath ، ولكن ليس ضروريًا) ، ثم قم بإنشاء كائن فئة من هذه العدوى.
(2) سوف يتحقق الرابط من رمز Bytecode في الفئة ويخصص مساحة التخزين للمجال الثابت. إذا لزم الأمر ، سيتم تحليل جميع الإشارات إلى الفصول الأخرى التي أنشأتها هذه الفئة.
(3) التهيئة إذا كان للفئة فئة فائقة ، وتهيئتها ، وتنفيذ التهيئة الثابتة وكتلة التهيئة الثابتة.
يتم تأخير التهيئة حتى المرجع الأول إلى طريقة ثابتة (يكون المُنشئ ثابتًا ضمنيًا) أو مجال ثابت غير مربع:
Class Data1 {Static Final int a = 1 ؛ ثابت نهائي مزدوج B = Math.Random () ؛ static {system.out.println ("init data1 ...") ؛ }} class data2 {static int a = 12 ؛ ثابت {system.out.println ("init data2 ...") ؛ }} class data3 {static int a = 23 ؛ static {system.out.println ("init data3 ...") ؛ }} الفئة العامة classtest2 {public static void main (string [] args) {system.out.println ("data1.class:") ؛ Data1 = data1.class ؛ system.out.println (data1.a) ؛ // data1 system.out.println (data1.b) ؛ // data1 initial system.out.println (data2.a) ؛ // data2 initial try {class data3 = class.forname ("com.itzhai.test.type.data3") ؛ // data3 initial} catch (classnotfoundException e) {system.out.println ("لا يمكن العثور على com.itzhai.test.type.data3 ...") ؛ } system.out.println (data3.a) ؛ }}نتيجة الإخراج هي:
Data1.Class: 1Init Data1 ... 0.26771085109184534Init Data2 ... 12Init Data3 ... 23
يحقق التهيئة بشكل فعال "كسول" قدر الإمكان.
2.5. فيما يلي بعض المواقف لتحديد ما إذا كنت تريد التهيئة:
(1) يحصل بناء جملة الفئة على إشارة إلى الفصل ولن يسبب التهيئة ؛
(2) class.forname () يولد مرجع الفصل ويتم تهيئته على الفور ؛
(3) إذا كانت القيمة النهائية الثابتة هي "ثابت للمترجم" ، فيمكن قراءة هذه القيمة دون تهيئة الفئة ؛
(4) لا يكفي ضمان هذا السلوك إذا فقط وضع مجال إلى نهائي ثابت ، على سبيل المثال:
ثابت نهائي مزدوج B = Math.Random () ؛
(5) إذا كان المجال الثابت هو بوشيفيالي ، ثم عند الوصول إليه ، تحتاج دائمًا إلى أن تكون مرتبطًا وتهيئًا ؛
2.6. اقتباس الطبقة المعممة:
يمثل مرجع الفئة النوع الدقيق للكائن الذي يشير إليه ، والكائن هو كائن للفئة الفئة. في Javase5 ، يمكن أن يكون كائن الفئة الذي يشير إليه مرجع فئة مؤهلاً من قبل الأدوية ، ويمكن للمترجم فرض اختبارات نوع إضافية:
intcls class = int.class ؛ // استخدم الأداء العام لتحديد المرجع الذي أشار إليه الفئة <integer> genintcls = int.class ؛ // يمكن إعادة تعيين الفئة بدون الأدوية العامة للإشارة إلى أي كائن فئة آخر intcls = double.class ؛ // sill error error // genintcls = double.class ؛
2.6.1. استخدم أحرف البدل؟ استرخ في قيود الأدوية:
فئة <؟> intcls = int.class ؛ intcls = string.class ؛
في Javase5 ، فئة <؟> أفضل من الفئة العادية ، ويوصى باستخدام الفئة <؟> حتى لو كانت متكافئة ، لأن ميزة الفئة <؟> هذا يعني أنك لا تحدث أو إهمالًا ، ولكن باستخدام مرجع فئة غير محدد.
لتحديد إشارة إلى فئة إلى نوع معين ، أو نوع فرعي من هذا النوع يمكن أن يستخدم البطاقات البرية مع تمديد ، إنشاء نطاق:
الفئة <؟ يمتد الرقم> num = int.class ؛ // النطاق المرجعي للرقم هو الرقم والفئة الفرعية الخاصة به ، بحيث يمكنك تعيين القيمة num = double.class ؛ num = number.class ؛
2.6.2. طريقة NewInstance () تحت الأدوية:
باستخدام الفئة بعد الأدوية الجينية ، يكون الكائن الذي يتم إرجاعه عن طريق استدعاء NewInstance () من النوع الدقيق ، ولكن عندما تستخدم GetSuperClass () للحصول على الفئة الفائقة المقابلة للعامة ، هناك بعض القيود على النوع الحقيقي: لا يعرف المترجم عن النوع Superclas
Dog Dog = dogcls.newInstance () ؛ مجردة Class Animal {} class class يمتد الحيوان {} // طريقة الكتابة التالية خاطئة ، ويمكنها فقط إعادة فئة <؟ super dog> type // class <imation> AnimalCls = dogcls.getSuperClass () ؛ الفئة <؟ Super Dog> AnimalCls = dogcls.getSuperClass () ؛ // من خلال مرجع الفئة الفائقة التي تم الحصول عليها ، يمكنك فقط إنشاء كائنات إرجاع كائن كائن Obj = AnimalCls.NewInstance () ؛ 2.6.3. بناء جملة التحويل الجديد: طريقة CAST ()
انظر مباشرة إلى الكود:
Animal Animal = new dog () ؛ class <Cog> dogcls = dog.class ؛ dog dogcls.cast (Animal) ؛ // أو استخدم بشكل مباشر طريقة التحول التالية Dog = (dog) Animal ؛
يمكن العثور على أن استخدام طريقة CAST () قد قام بعمل إضافي. يمكن استخدام طريقة التحويل هذه في الموقف التالي: عند كتابة نطاق عام ، إذا تم تخزين مرجع الفصل وتأمل في إجراء التحول من خلال مرجع الفئة هذا ، يمكنك استخدام طريقة CAST ().
3. اكتب مثيل التحقق من
3.1. تحقق قبل تحويل الكتابة
يتيح لك برنامج التحويل البرمجي إجراء عمليات تخصيص التحول التصاعدي بحرية دون أي عمليات تحويل معروضة ، تمامًا مثل تعيين القيم للمراجع إلى فئات فائقة.
ومع ذلك ، إذا لم يتم استخدام تحويل النوع المعروض ، فلن يسمح لك برنامج التحويل البرمجي بإجراء مهمة الانتقالات المتساوية. في هذا الوقت ، قد نتحقق من ما إذا كان الكائن مثيلًا لنوع معين ، ومثيل الكلمة الرئيسية للكلمة الرئيسية:
if (x eastyof dog) ((dog) x) .bark () ؛
3.2. شكل RTTI:
لذلك ، حتى الآن ، نعلم أن أشكال RTTI تشمل:
(1) تحويل النوع التقليدي (الشكل)
(2) كائن فئة يمثل نوع الكائن
(3) مثيل الكلمة الرئيسية
3.3. طريقة مثيل ديناميكي:
توفر طريقة class.isinstance طريقة لاختبار الكائنات ديناميكيًا.
ما يلي يوضح استخدام مثيل و class.isinstance:
يصف:
سمة الواجهة العامة {}شكل:
/** * قم بإنشاء فئة مجردة */شكل فئة مجردة عامة {// هذا يستدعي طريقة toString لطريقة toString الحالية للحصول على معلومات الفراغ العام draw () {system.out.println (this + ".draw ()") ؛ } // إعلان طريقة tostring () إلى الملخص ، وبالتالي إجبار الوراثة على إعادة كتابة هذه الطريقة. المجردة السلسلة العامة tostring () ؛}دائرة:
يمتد دائرة الفئة العامة للأدوات السمة {public string toString () {return "circle" ؛ }}مربع:
يمتد مربع الفئة العامة الشكل {public string tostring () {return "square" ؛ }}مثلث:
يمتد مثلث الفئة العامة الشكل {public string tostring () {return "triangle" ؛ }}اكتب التحقق:
// easuleofcircle c = new circle () ؛ // حدد ما إذا كان مثيل superclass system.out.format ("باستخدام مثيل: ٪ s هو شكل؟ ٪ b/n" ، Superclass System.out.format ("باستخدام class.isinstance: ٪ s هو شكل؟ ٪ b/n" ، c.toString () ، c estance exateof circle) ؛ System.out.format ("باستخدام class.isinstance: ٪ s هي سمة؟ ٪ b/n" ، c.toString () ، attribute.class.isinstance (c)) ؛يمكن العثور على أن طريقة OF أو CLASS.ISINSTANCE تحدد ما إذا كانت ترث مثيلًا للنظام ، أي ، بالإضافة إلى الحكم على نفسه ، تحدد أيضًا ما إذا كانت فائقة أو مثيل للواجهة.
يوضح ما يلي كيفية استخدام class.instance الديناميكي:
أولا قم بإنشاء فئة مولد شكل مجردة:
فئة مجردة عامة Shapecreator {Private Random Rand = New Random (10) ؛ // إرجاع مجموعة من أنواع الكائنات التي توفرها فئة التنفيذ. سترى نموذجين للتنفيذ لاحقًا ، استنادًا إلى Forname واستنادا إلى الثوابت الحرفية الفئة. قائمة الملخصات العامة <؟ يمتد الشكل >> الأنواع () ؛ // قم بإنشاء مثيل كائن النوع بشكل عشوائي في مجموعة من أنواع الكائنات ، الشكل العام randomshape () {int n = rand.nextint (types (). size ()) ؛ جرب {return types (). get (n) .NewInstance () ؛ } catch (InstantiationException e) {e.printStackTrace () ؛ العودة لاغية. } catch (alfictAccessException e) {e.printStackTrace () ؛ العودة لاغية. }} // قم بإنشاء شكل عام عشوائي [] CreateArray (int size) {theme [] result = new mape [size] ؛ لـ (int i = 0 ؛ i <size ؛ i ++) {result [i] = randomshape () ؛ } نتيجة الإرجاع ؛ } // إنشاء صفيف عشوائي ، ArrayList عام ArrayList Public ArrayList <Mape> ArrayList (int size) {ArrayList <Phary> result = new ArrayList <Phary> () ؛ collections.addall (النتيجة ، CreateArray (size)) ؛ نتيجة العودة }}بعد ذلك ، اكتب تطبيقًا لهذه الفئة التجريدية:
/** * تطبيق المولد forname * Author Artinking * */فئة Public Fornamecreator يمتد Shapecreator {قائمة ثابتة خاصة <class <؟ يمتد الشكل >> أنواع = ArrayList جديد <class <؟ يمتد الشكل >> () ؛ سلسلة ثابتة خاصة [] typenames = {"com.itzhai.javanote.entity.circle" ، "com.itzhai.javanote.entity.square" ، "com.itzhai.javanote.entity.triangle"} ؛ suppressWarnings ("unused") private static void loader () {for (اسم السلسلة: typenames) {try {types.add ((class <؟ extends forme>) class.forname (name)) ؛ } catch (classNotFoundException e) {E.PrintStackTrace () ؛ }}} // تهيئة صفيف الأنواع المطلوبة لتحميل {loader () ؛ } القائمة العامة <class <؟ يمتد الشكل >> أنواع () {أنواع الإرجاع ؛ }}أخيرًا ، اكتب فصلًا يحسب عدد الأشكال ، باستخدام مثيل:
الفئة العامة ShapeCount {static class Shapecounter يمتد hashmap <string ، integer> {public void count (نوع السلسلة) {integer Quantity = get (type) ؛ if (Quantity == null) {put (type ، 1) ؛ } آخر {put (type ، Quantity + 1) ؛ }}} // إظهار أنواع الكائنات الصلغة من خلال مثيل الكلمة الأساسية الكلمة العامة الثابتة الفراغ الثابتة (apphecreator creator) {Shapecounter Counter = new ShapeCounter () ؛ لـ (شكل الشكل: Creator.CreateArray (20)) {if (شكل مثيل من دائرة) counter.count ("Circle") ؛ if (شكل مثيل من مربع) counter.count ("مربع") ؛ if (شكل مثيل triangle) {counter.count ("triangle") ؛ }} system.out.println (counter) ؛ } public static void main (string [] args) {countShapes (new fornamecreator ()) ؛ }}أعد كتابة تنفيذ الطبقة التجريدية وإعادة تنفيذها مع الثوابت الحرفية الطبقية:
/*** تنفيذ المولد الحرفي*/فئة Public Class MiteralCreator يمتد Shapecreator {القائمة النهائية الثابتة العامة <الفئة <؟ يمتد الشكل >> alltype = collections.unmodifiablElist (Arrays.aslist (circle.class ، triangle.class ، square.class)) ؛ القائمة العامة <الفئة <؟ يمتد الشكل >> الأنواع () {return alltype ؛ } public static void main (string [] args) {system.out.println (alltype) ؛ }}استخدم الآن class.instance لحساب عدد الأشكال على النحو التالي:
/*** قم بإزالة بيان مثيل Renotonic في ShapeCount الأصلي باستخدام class.instanceof كائن الاختبار الديناميكي**/الفئة العامة ShapeCount2 {القائمة النهائية الثابتة الخاصة <؟ يمتد الشكل >> appetypes = حرفي creator.alltype ؛ static class appecounter يمتد hashmap <string ، integer> {public void count (نوع السلسلة) {integer Quantity = get (type) ؛ if (Quantity == null) {put (type ، 1) ؛ } آخر {put (type ، Quantity + 1) ؛ }}} // إظهار أنواع الكائنات الإحصائية من خلال class.isinstance () countshapes public static static void (apphecreator) {appeceCounter counter = new ShapeCounter () ؛ لـ (شكل الشكل: Creator.CreateArray (20)) {for (class <؟ تمديد الشكل> cls: dapeetypes) {if (cls.isinstance (form)) {counter.count (cls.getSimplename ()) ؛ }} system.out.println (counter) ؛ } public static void main (string [] args) {countShapes (new fornamecreator ()) ؛ }}الآن هناك تطبيقان للمولد. يمكننا إضافة طبقة من المظهر هنا وتعيين طريقة التنفيذ الافتراضية:
/*** الآن هناك تطبيقان للمولد. دعنا نضيف طبقة من المظهر هنا ونضع طريقة التنفيذ الافتراضية */أشكال الفئة العامة {Public Static Final Final Creator = New ListeralCreator () ؛ شكل ثابت عام عشوائي () {return Creator.RandomShape () ؛ } الشكل الثابت العام [] CreateArray (int size) {return creator.createarray (size) ؛ } ArrayList static static <Sume> ArrayList (int size) {return creator.arrayList (size) ؛ }} 3.4. معادلة مثيل والفئة:
النتيجة التي تم إنشاؤها بواسطة مثيل و isInstance () هي نفسها تمامًا ، حيث تحافظ على مفهوم النوع وتحديد ما إذا كانت فئة أو فئة مشتقة من هذه الفئة.
يساوي () هو نفسه == ، واستخدام هذا الكائن الطبقي الأكثر عملية ، لا يتم النظر في الميراث.
System.out.println (New Circle () مثيل Circle) ؛ // truestystem.out.println (lape.class.isinstance (New Circle ())) ؛ // truestystem.out.println ((New Circle ()). getClass () == Circle.Class) ؛ // truestystem.out.println ((New Circle (). getClass ()). equals (mapace.class)) ؛ // خطأ شنيع