تهدف هذه المقالة إلى تقديم مقدمة شاملة لآلية انعكاس Java. آمل أنه من خلال هذا المقال ، سيكون لديك فهم شامل للمحتوى ذي الصلة لتفكير Java.
قبل قراءة هذا المقال ، يمكنك الرجوع إلى " إعادة فهم جافا جيركس " .
مقدمة
آلية انعكاس Java هي وظيفة قوية للغاية. يمكن رؤية الانعكاسات في العديد من المشاريع واسعة النطاق مثل Spring و MyBatis. من خلال آلية الانعكاس ، يمكننا الحصول على معلومات نوع الكائن أثناء التشغيل. باستخدام هذه الميزة ، يمكننا تنفيذ أنماط التصميم مثل وضع المصنع ووضع الوكيل ، ويمكننا أيضًا حل المشكلات المحزنة مثل محو جافا العام. في هذه المقالة ، سنطبق آلية انعكاس Java من منظور التطبيقات العملية.
أساس الانعكاس
ملاحظة: تتطلب هذه المقالة من القراء الحصول على درجة معينة من فهم آلية آلية الانعكاس. إذا لم تتعرض لها من قبل ، فمن المستحسن النظر في البداية السريعة للوثيقة الرسمية أولاً.
قبل تطبيق آلية الانعكاس ، دعونا نلقي نظرة أولاً على كيفية الحصول على Class الانعكاس المقابلة لكائن ما. في Java ، لدينا ثلاث طرق للحصول على فئة الانعكاس للكائن.
بواسطة طريقة getClass
في Java ، كل Object لديه طريقة getClass . من خلال طريقة getClass ، يمكننا الحصول على فئة الانعكاس المقابلة لهذا الكائن:
String s = "ziwenxie" ؛ class <؟> c = s.getClass () ؛
يمكننا أيضًا استدعاء الطريقة الثابتة forName Class :
class <؟> c = class.forname ("java.lang.string") ؛ أو يمكننا استخدام .class مباشرة:
فئة <؟> c = string.class ؛
في بداية المقالة ، ذكرنا أن إحدى الفوائد الرئيسية للانعكاس هي أنها تسمح لنا بالحصول على معلومات نوع الكائن أثناء التشغيل. دعونا نلقي نظرة عليه بالتفصيل مع مثال.
أولاً ، نقوم بإنشاء واجهة جديدة A تحت حزمة typeinfo.interfacea :
package typeinfo.Interfacea ؛ public interface a {void f () ؛ } ثم نقوم بإنشاء واجهة جديدة C ضمن حزمة typeinfo.packageaccess . ترث الواجهة C من الواجهة A ، وقمنا أيضًا بإنشاء عدة طرق أخرى للاختبار. لاحظ أن أذونات الأساليب التالية مختلفة.
package typeinfo.packageAccess ؛ استيراد typeinfo.interfacea.a ؛ الفئة C تنفذ {public void f () {system.out.println ("public cf ()") ؛ } public void g () {system.out.println ("public cg ()") ؛ } void v () {system.out.println ("CV () محمية ()") ؛ } void u () {system.out.println ("package cu ()") ؛ } private void w () {system.out.println ("private cw ()") ؛ }} الفئة العامة hiddenc {public static a makea () {return new c () ؛ }} في طريقة callHiddenMethod() ، نستخدم العديد من واجهات برمجة التطبيقات الجديدة ، حيث يتم استخدام getDeclaredMethod() للحصول على طريقة تشير فئة الفصل إلى الكائن وفقًا لاسم الطريقة ، ثم يمكننا تشغيل الأساليب ذات الصلة بالكائن عن طريق استدعاء طريقة invoke() :
package typeinfo ؛ import typeinfo.interfacea AF () ؛ System.out.println (A.GetClass (). getName ()) ؛ // أُووبس! لا يزال الانعكاس يسمح لنا بالاتصال G (): callhiddenmethod (A ، "G") ؛ // وحتى الأساليب التي يمكن الوصول إليها أقل! callhiddenmethod (a ، "u") ؛ Callhiddenmethod (A ، "V") ؛ Callhiddenmethod (A ، "W") ؛ } static void callhiddenmethod (Object A ، String methodName) يلقي الاستثناء {method g = a.getClass (). getDeclaredMethod (methodName) ؛ G.SetAccessible (صحيح) ؛ G.invoke (A) ؛ }} من نتائج الإخراج ، يمكننا أن نرى أنه سواء كانت طريقة public أو default أو protect أو pricate ، يمكننا أن نسميها بحرية من خلال فئة الانعكاس. بالطبع ، نحن فقط لإظهار القوة القوية للانعكاس ، ولا ينصح هذه التقنية في التطوير الفعلي.
CF () public typeinfo.packageaccess.cpublic cg () package cu () CV () CW () CW () Private CW () CW ()
لدينا سيناريو العمل التالي. لدينا List<Class<? extends Pet>> . نحتاج إلى حساب عدد Pet المحددة في فئة المجموعة هذه. بسبب محو جافا العام ، من المؤكد أنه من غير الممكن الانتباه إلى الممارسة المشابهة List<? extends Pet> ، لأنه بعد فحص المترجم النوع الثابت ، سوف يعامل JVM جميع الكائنات في المجموعة Pet أثناء التشغيل ، لكنه لن يعرف ما إذا كان Pet يمثل Cat أو Dog ، وبالتالي فإن معلومات النوع للكائن قد فقدت بالفعل أثناء التشغيل. ملاحظة: حول المحو العام: لدي شرح مفصل في المقالة السابقة. يمكن للأصدقاء المهتمين إلقاء نظرة.
لتنفيذ مثالنا أعلاه ، نحدد أولاً عدة فئات:
يمتد PET PRECLES PET الفردي {public pet (اسم السلسلة) {super (name) ؛ } pet pet () {super () ؛ }} Class Clas Public Cat تمتد PET {public cat (اسم السلسلة) {super (name) ؛ } public cat () {super () ؛ }} class class public يمتد pet {public dog (اسم السلسلة) {super (name) ؛ }} الفئة العامة المصرية يمتد Cat {Public Legyptianmau (اسم السلسلة) {super (name) ؛ } المصري العام () {super () ؛ }} الفئة العامة mutt يمتد الكلب {public mutt (اسم السلسلة) {super (name) ؛ } public mutt () {super () ؛ }} فئة Pet أعلاه ترث من Individual . تنفيذ الطبقة Individual أكثر تعقيدًا. قمنا بتنفيذ الواجهة Comparable وقمنا بإعادة تعريف قواعد مقارنة الفصل. إذا لم نفهمها جيدًا ، فلا يهم. لقد استخلصناها ، لذلك لا يهم إذا لم نفهم مبدأ التنفيذ.
تطبيقات الفئة العامة الفردية قابلة للمقارنة <SERNOM> {عداد طويل ثابت طويل = 0 ؛ معرف نهائي خاص = Counter ++ ؛ اسم السلسلة الخاصة ؛ // الاسم هو فرد عام اختياري (اسم السلسلة) {this.name = name ؛ } الفرد العام () {} السلسلة العامة toString () {return getClass (). getSimplename () + (name == null؟ "": "" + name) ؛ } المعرف العام العام () {معرف الإرجاع ؛ } منطقية عامة تساوي (كائن O) {return o eastyof very && id == ((فردية) o) .id ؛ } public int hashcode () {int result = 17 ؛ if (name! = null) {result = 37 * result + name.hashCode () ؛ } النتيجة = 37 * النتيجة + (int) معرف ؛ نتيجة العودة } public int compareto (فردي arg) {// قارن حسب اسم الفئة أولاً: String first = getClass (). getMplename () ؛ String Argfirst = arg.getClass (). getSimplename () ؛ int firstCompare = first.compareto (ArgFirst) ؛ if (firstCompare! = 0) {return firstCompare ؛ } if (name! = null && arg.name! = null) {int SecondaryCompare = name.compareto (arg.name) ؛ if (SecendCompare! = 0) {return SecondaryCompare ؛ }} return (arg.id <id؟ -1: (arg.id == id؟ 0: 1)) ؛ }} أدناه هو PetCreator من فئة مجردة. في المستقبل ، يمكننا الحصول مباشرة على مجموعة من فئات Pet ذات الصلة من خلال استدعاء طريقة arrayList() . هنا نستخدم طريقة newInstance() التي لم نذكرها أعلاه. سيعود مثيلًا للفصل الذي يشير إليه الفصل الدراسي حقًا. ماذا يعني هذا؟ على سبيل المثال ، إن إعلان الكلب الجديد new Dog() new Dog().getClass().newInstance()
Public Class Petcreator {Private Random Rand = New Random (47) ؛ // قائمة GetTypes المختلفة للحيوانات الأليفة لإنشاء: قائمة الملخص العامة <class <؟ يمتد PET >> gettypes () ؛ Public Pet Randompet () {// إنشاء PET عشوائي واحد int n = rand.nextint (getTypes (). size ()) ؛ حاول {return gettypes (). get (n) .NewInstance () ؛ } catch (instantiationException e) {رمي new RunTimeException (e) ؛ } catch (alfictAccessException e) {refl new RunTimeException (e) ؛ }} pet pet [] createArray (int size) {pet [] result = new pet [size] ؛ لـ (int i = 0 ؛ i <size ؛ i ++) {result [i] = randompet () ؛ } نتيجة الإرجاع ؛ } ArrayList Public <TEP> ArrayList (int size) {ArrayList <Pet> result = new ArrayList <Pet> () ؛ collections.addall (النتيجة ، CreateArray (size)) ؛ نتيجة العودة }} بعد ذلك ، دعنا ننفذ الفئة المجردة أعلاه وشرح الكود التالي. في الكود التالي ، نعلن عن فئتين للتجميع ، allTypes types ، من بينها جميع allTypes التي تحتوي على جميع الفصول المعلنة أعلاه ، ولكن أنواعنا المحددة هي في الواقع نوعان فقط ، وهما Mutt و EgypianMau ، وبالتالي فإن الحيوانات الأليفة التي نحتاجها حقًا للحصول على new هو الأنواع الواردة في types . في المستقبل ، يمكننا الحصول على الأنواع الواردة في types عن طريق استدعاء getTypes() .
الطبقة العامة الحرفية يمتد PetCreator {suppressWarnings ("Unchecked") القائمة النهائية الثابتة العامة <الفئة <؟ يمتد PET >> alltypes = collections.unmodifiablElist (Arrays.aslist (pet.class ، dog.class ، cat.class ، mutt.class ، egyptianmau.class)) ؛ القائمة النهائية الثابتة الخاصة <class <؟ يمتد PET >> أنواع = alltypes.sublist (alltypes.indexof (mutt.class) ، alltypes.size ()) ؛ القائمة العامة <الفئة <؟ يمتد PET >> gettypes () {أنواع الإرجاع ؛ }} تم الانتهاء من المنطق الكلي ، وأخيراً نقوم بتنفيذ فئة TypeCounter المستخدمة لحساب عدد فئات Pet ذات الصلة في المجموعة. اشرح طريقة isAssignalbeFrom() ، والتي يمكن أن تحدد أن فئة الانعكاس هي فئة فرعية أو فئة فرعية غير مباشرة لفئة الانعكاس. كما يوحي الاسم ، getSuperclass() هو الحصول على فئة الوالدين لفئة الانعكاس.
الطبقة العامة typecounter يمتد hashmap <class <؟> ، integer> {private class <؟> basetype ؛ typecounter العامة (الفئة <؟> basetype) {this.baseType = basetype ؛ } عدد الفراغ العام (كائن OBJ) {class <؟> type = obj.getClass () ؛ if (! baseType.ISASASIGNABLEFROM (type)) {رمي new RunTimeException (OBJ + "type type" + type + "، يجب أن يكون نوعًا أو نوعًا فرعيًا لـ" + basetype) ؛ } countClass (type) ؛ } private void countClass (class <؟> type) {integer Quantity = get (type) ؛ ضع (النوع ، الكمية == فارغ؟ 1: الكمية + 1) ؛ الفئة <؟> superclass = type.getSuperClass () ؛ if (superclass! = null && baseType.ISASSIGNABLEFROM (superclass)) {countClass (superclass) ؛ }} Override public string toString () {StringBuilder result = new StringBuilder ("{") ؛ لـ (map.entry <class <؟> ، integer> pair: interptset ()) {result.append (pair.getKey (). getSimplename ()) ؛ result.append ("=") ؛ result.append (pair.getValue ()) ؛ result.append ("،") ؛ } result.delete (result.length () - 2 ، result.length ()) ؛ result.append ("}") ؛ return return.toString () ؛ }}لخص
ما سبق هو كل محتوى هذه المقالة حول مثال مشاركة رمز آلية انعكاس Java ، وآمل أن يكون مفيدًا للجميع. يمكن للأصدقاء المهتمين الاستمرار في الرجوع إلى هذا الموقع:
رمز تنفيذ إيصال التسوق Java وطباعة
شرح مفصل لتنفيذ المراجع والوكيل الديناميكي في جافا
برمجة Java لتنفيذ مشاركة رمز بسيطة من القمر Eclipse
إذا كانت هناك أي أوجه قصور ، فيرجى ترك رسالة لإشارةها. شكرا لك يا أصدقائك لدعمكم لهذا الموقع!