ما هو الانعكاس
"يسمح الانعكاس برامج تعمل في JVM للكشف عن سلوك وقت التشغيل وتعديله." غالبًا ما يتم الخلط بين هذا المفهوم مع التأمل. فيما يلي تفسيرات هذين المصطلحين في ويكيبيديا:
مثال على الاستبطان: يتم استخدام عامل التشغيل من أجل اكتشاف ما إذا كان الكائن ينتمي إلى فئة محددة.
if (obj extryof dog) {dog d = (dog) obj ؛ D.Bark () ؛}مثال الانعكاس: يمكن للطريقة class.forname () الحصول على كائن الفئة المقابل من خلال اسم الفئة أو الواجهة (سلسلة أو اسم مؤهل بالكامل). طريقة اسم forname تؤدي إلى تهيئة الفصل.
// استخدم فئة الانعكاس <؟> c = class.forname ("classpath.and.className") ؛ الكائن الكائن =في Java ، يكون الانعكاس أقرب إلى التأمل لأنه لا يمكنك تغيير بنية كائن ما. على الرغم من أنه يمكن استخدام بعض واجهات برمجة التطبيقات لتعديل رؤية الأساليب والخصائص ، إلا أنها لا تستطيع تعديل الهياكل.
انعكاس المصفوفات
ما هو استخدام انعكاس صفيف؟ متى تحتاج إلى استخدام انعكاس المصفوفات؟ لنلقي نظرة على الكود التالي:
integer [] nums = {1 ، 2 ، 3 ، 4} ؛ كائن [] objs = nums ؛ // يمكن تحويله تلقائيًا إلى عدد صحيح [] إلى كائن [] Object obj = nums ؛ // integer [] بالطبع كائن int [] ids = {1 ، 2 ، 3 ، 4} ؛ // object [] objs2 = ids ؛ // لا يمكن تحويل int [] إلى كائن [] Object OBJ2 = ids ؛ // int [] هو كائنيوضح المثال أعلاه أن نوعًا أساسيًا من الصفيف أحادي البعد لا يمكن اعتباره إلا ككائن ، وليس ككائن [].
int [] [] Intarray = {{1 ، 2} ، {3 ، 4}} ؛ كائن [] OA = Intarray ؛ كائن OBJ = Intarray ؛ // integer [] [] integerArray = Intarray ؛ int [] [] not integer [] [] integer [] [] integerArray2 = new integer [] [] {1 ، 2} ، {3 ، 4}} ؛ Object [] [] OA2 = IntegerArray2 ؛ Object [] OA3 = integerArray2 ؛ كائن obj2 = integerArray2 ؛من المثال أعلاه ، يمكننا أن نرى أن مجموعة من رقمين من Java هي مجموعة من المصفوفات. دعونا نلقي نظرة على مثال عكس صفيف:
حزمة cn.zq.array.reflect ؛ استيراد java.lang.reflect.array ؛ استيراد java.util.arrays ؛ استيراد java.util.random ؛ الطبقة العامة arrayReflect {public static void main (string [] args) {Random Rand = new Random (47) ؛ int [] هو = جديد int [10] ؛ لـ (int i = 0 ؛ i <is.length ؛ i ++) {iS [i] = rand.nextint (100) ؛ } system.out.println (IS) ؛ System.out.println (Arrays.aslist (IS)) ؛ /*المخرجان أعلاه هما سلاسل مشابهة لـ "[[I@14318bb]" ، والتي لا يمكن عرض المحتوى المخزن في الصفيف. بالطبع ، نستخدم اجتيازًا لإخراج المحتويات في الصفيف*/ system.out.println ("-1. اجتياز الصفيف عن طريق الطباعة-") ؛ لـ (int i = 0 ؛ i <is.length ؛ i ++) {system.out.print (is [i]+"") ؛ } system.out.println () ؛ System.out.println ("-2. اجتياز إلى المصفوفة عن طريق الطباعة-") ؛ كائن obj = هو ؛ // تحويل صفيف int أحادي البعد إلى كائن system.out.println ("OBJ isarray:" + obj.getClass (). isarray ()) ؛ لـ (int i = 0 ؛ i <array.getLength (obj) ؛ i ++) {int num = array.getInt (obj ، i) ؛ // يمكنك أيضًا استخدام هذه الطريقة الشائعة الاستخدام للحصول على قيمة موضع الفهرس المقابل//قيمة الكائن = Array.get (obj ، i) ؛ // إذا قام المصفوفة بتخزين النوع الأساسي ، فعندئذ نوع التفاف المقابل لنظام النوع الأساسي. out.print (num + "") ؛ }}}الإخراج:
[i@14318bb [[i@14318bb] -1. اطبع الصفيف عن طريق اجتياز الصفيف بالوسائل التقليدية-58 55 93 61 61 29 68 0 22 7-2. اطبع المصفوفة عن طريق اجتياز الصفيف عن طريق اجتياز الصفيف من خلال اجتياز المصفوفة- OBJ Isarray: True 58 55 93 61 61 29 68 0 22 7
يقوم المثال أعلاه أولاً بإنشاء صفيف أحادي البعد من int ، ثم يملأ بشكل عشوائي عدد صحيح من 0 ~ 100. بعد ذلك ، قم بإخراج الصفيف مباشرة من خلال system.out.println () أو استخدام المصفوفات. Aslist Method (إذا لم تكن مجموعة أحادية البعد من الأنواع الأساسية ، يمكن تحويل هذه الطريقة إلى القائمة كما هو متوقع ، وإذا كانت صفيف ثنائي الأبعاد ، فلا يمكن تحويلها إلى القائمة كما نتوقع). يتم تحويل الصفيف إلى قائمة ثم الإخراج ، والتمرير ليس نتيجة الإخراج التي نتوقعها. بعد ذلك ، يتم إخراج المحتويات الموجودة في الصفيف في طريقة اجتياز الصفيف العادية ، ثم تعامل مع int [] ككائن ، واستخدم انعكاسًا لتجاوز محتواه. يمكن استخدام class.isarray () لتحديد ما إذا كان الكائن عبارة عن صفيف. إذا كانت صفيفًا ، فسيتم الحصول على المعلومات ذات الصلة من الصفيف من خلال java.lang.reflect.array ، وهي فئة أدوات تعكس الصفيف. يستخدم هذا الفئة بعض الطرق للحصول على طول الصفيف ، يتم استخدام كل إصدار منها للحصول على الفهرس المقابل للمصفوفة أحادية البعد من الأنواع الأساسية ، وطريقة عامة للحصول على القيمة (صفيف الكائن ، وفهرس int) ، وطريقة لتعيين القيمة ، وطريقتين لإنشاء مثيلات الصفيف. من خلال فئة أداة انعكاس الصفيف ، من السهل استخدام انعكاس المصفوفة لكتابة الكود العام دون الحكم على أي نوع أساسي من الصفيف هو المصفوفة المحددة.
حزمة cn.zq.array.reflect ؛ استيراد java.lang.reflect.array ؛ الفئة العامة newarrayinstance {public static void main (string [] args) {object o = array.newinstance (int.class ، 20) ؛ int [] هو = (int []) o ؛ System.out.println ("iS.Length =" + IS.Length) ؛ كائن O2 = Array.newinstance (int.class ، 10 ، 8) ؛ int [] [] ISS = (int [] []) O2 ؛ System.out.println ("iss.length =" + iss.length + "، ISS [0] .lenght =" + ISS [0] .Length) ؛ }} is.length = 20 ISS.Length = 10 ، ISS [0] .Lenght = 8 مرت الصفيف بطريقتين لإنشاء صفيف
Object NewInstance (Class <؟> ComponentType ، طول int) ، قم بإنشاء مجموعة من الطول المحدد بناءً على الفئة المقدمة. إذا تم توفير int.class على النحو الوارد أعلاه ، فإن الطول هو 10 ، وهو ما يعادل New Int [10] ؛
Object NewInstance (Class <؟> ComponentType ، int ... الأبعاد) ، ينشئ صفيفًا يعتمد على الفئة والأبعاد المقدمة. يتم استخدام أبعاد المعلمة المتغيرة لتحديد طول كل بعد من الصفيف. كما هو الحال في المثال أعلاه ، فإنه يعادل إنشاء صفيف ثنائي الأبعاد من int الجديد [10] [8] ، لكنه لا يمكنه إنشاء مجموعة متعددة الأبعاد بأطوال مختلفة من كل بعد. من خلال الطريقة الأولى لإنشاء صفيف ، يمكنك إنشاء صفيف مثل هذا. الكائن O = Array.NewInstance (int []. الفئة ، 20) يمكن استخدامه لإنشاء صفيف ثنائي الأبعاد ، وهو ما يعادل الكائن O = جديد int [20] [] ؛
بالطبع ، من النادر استخدام المثال أعلاه لإنشاء صفيف ، ولكنه زائد بالفعل. لماذا لا تنشئ صفيفًا مباشرة من خلال جديد؟ ينشئ الانعكاس صفيفًا ليس فقط أسرع من الجديد ، ولكن أيضًا ليس من السهل قراءته البرنامج المكتوب ، لذلك ليس مباشرًا بنفس القدر. في الواقع ، من النادر حقًا إنشاء صفائف من خلال التفكير. أي نوع من الاحتياجات غير الطبيعية موجودة لاستخدام التفكير لإنشاء صفائف!
نظرًا لأن بعض العقبات تمت عند إخراج مجموعة من الأنواع الأساسية ، فإن ما يلي سيستخدم انعكاس الصفيف لتنفيذ فئة الأدوات لتحقيق الإخراج المطلوب:
حزمة cn.zq.util ؛ استيراد java.io.bytearrayoutputstream ؛ استيراد java.io.printstream ؛ استيراد java.lang.reflect.array ؛ طباعة الفئة العامة {public static void print (Object obj) {print (obj ، system.out) ؛ } طباعة باطلة ثابتة (كائن OBJ ، printstream out) {out.println (getPrintString (obj)) ؛ } println println () {print (system.out) ؛ } println println static println (printstream out) {out.println () ؛ } printnb printnb (Object Obj) {printnb (obj ، system.out) ؛ } printnb printnb (Object Obj ، printstream out) {out.print (getPrintString (obj)) ؛ } تنسيق printstream الثابت العام (تنسيق السلسلة ، الكائن ... الكائنات) {return format (system.out ، التنسيق ، الكائنات) ؛ } تنسيق printstream الثابت العام (printstream out ، تنسيق السلسلة ، الكائنات ... الكائنات) {object [] GELENTOBJECTS = new Object [Objects.length] ؛ لـ (int i = 0 ؛ i <objects.length ؛ i ++) {object = objects [i] ؛ if (object == null || isprimitiveWrapper (Object)) {GallEbjects [i] = Object ؛ } else {bytearrayoutputstream bos = new bytearrayoutputstream () ؛ printstream ps = new printstream (BOS) ؛ printnb (كائن ، ps) ؛ Ps.Close () ؛ HandleObjects [i] = سلسلة جديدة (bos.tobytearray ()) ؛ }} out.format (التنسيق ، handbjects) ؛ العودة } /*** حدد ما إذا كان كائن معين عبارة عن فئة غلاف من النوع الأساسي. * param o كائن كائن معطى * regurn إذا كانت فئة غلاف من الأنواع البدائية ، إرجاع نعم ، وإلا إرجاع رقم */ خاص iSprimitiveWrapper (كائن O) o مثيل من منطقية || O extryof حرف || o مثيل بايت || o مثيل قصير || o مثيل integer || o مثيل طويل || o exateof float || o مثيل مضاعف ؛ } السلسلة الثابتة العامة getPrintString (Object OBJ) {StringBuilder result = new StringBuilder () ؛ if (obj! = null && obj.getClass (). isArray ()) {result.append ("[") ؛ int len = array.getLength (OBJ) ؛ لـ (int i = 0 ؛ i <len ؛ i ++) {comfort value = array.get (obj ، i) ؛ result.append (getPrintString (value)) ؛ if (i! = len - 1) {result.append ("،") ؛ }} result.append ("]") ؛ } آخر {result.append (string.valueof (obj)) ؛ } return result.toString () ؛ }}توفر فئة أداة الطباعة أعلاه بعض الطرق الثابتة العملية للإخراج ، وتوفر بعض الإصدارات الزائدة. يمكنك كتابة بعض الإصدارات الزائدة بناءً على تفضيلاتك الشخصية ، ودعم طباعة الأنواع الأساسية من المصفوفات أحادية البعد والصفائف متعددة الأبعاد. انظر الأمثلة التالية لاختبار أداة الطباعة:
حزمة cn.zq.array.reflect ؛ استيراد static cn.zq.util.print.print ؛ استيراد java.io.printstream ؛ استيراد static cn.zq.util.print.*؛ الطبقة العامة printtest {static class person {private static int counter ؛ معرف int النهائي الخاص = counter ++ ؛ السلسلة العامة toString () {return getClass (). getSimplename () + id ؛ }} public static void main (string [] args) يرمي الاستثناء {print ("-طباعة غير وارايا-") ؛ طباعة (كائن جديد ()) ؛ طباعة ("-طباعة مجموعة أحادية البعد من الأنواع الأساسية-") ؛ int [] هو = جديد int [] {1 ، 22 ، 31 ، 44 ، 21 ، 33 ، 65} ؛ طباعة (IS) ؛ طباعة ("-طباعة مجموعة ثنائية الأبعاد من الأنواع الأساسية-") ؛ int [] [] iss = new int [] [] {{11 ، 12 ، 13 ، 14} ، {21 ، 22 ،} ، {31 ، 32 ، 33}} ؛ طباعة (ISS) ؛ طباعة ("-طباعة مجموعة أحادية البعد من الأنواع غير القاعدية-") ؛ شخص [] أشخاص = شخص جديد [10] ؛ لـ (int i = 0 ؛ i <propons.length ؛ i ++) {persons [i] = new person () ؛ } طباعة (أشخاص) ؛ طباعة (أشخاص) ؛ طباعة ("-طباعة مجموعة ثنائية الأبعاد من الأنواع غير المحددة-") ؛ person [] [] [] persons2 = شخص جديد [] [] {{new person ()} ، {new person () ، new person ()} ، {new person () ، new person () ، new person () ، new person () ،} ،} ؛ طباعة (أشخاص 2) ؛ طباعة ("-طباعة صفيف فارغ-") ؛ print (new int [] {}) ؛ طباعة ("-طباعة صفيف مع قيم خالية-") ؛ Object [] Objects = New Object [] {new person () ، null ، new Object () ، integer (100)} ؛ طباعة (كائنات) ؛ طباعة ("-طباعة صفيف ثنائي الأبعاد للحالات الخاصة-") ؛ Object [] [] objects2 = كائن جديد [3] [] ؛ Objects2 [0] = كائن جديد [] {} ؛ الكائنات 2 [2] = الكائنات ؛ طباعة (كائنات 2) ؛ طباعة ("-إخراج نتيجة الصفيف أحادي البعد إلى الملف-") ؛ printstream out = new printstream ("Out.C") ؛ حاول {print (ISS ، Out) ؛ } أخيرًا {out.close () ؛ } print ("-Format Output--") ؛ التنسيق ("٪-6d ٪ s ٪ b ٪ s" ، 10086 ، "هو" ، صحيح ، ISS) ؛ /** * يتم سرد بعض طرق فئات أدوات الطباعة الشائعة الاستخدام أعلاه ، * هناك أيضًا بعض الطرق غير المدرجة ، يرجى التحقق من ذلك بنفسك. */}} الإخراج:
--Print nonarray-java.lang.object@61de33-طباعة مجموعة أحادية البعد من الأنواع الأساسية-[1 ، 22 ، 31 ، 44 ، 21 ، 33 ، 65]-صفيف ثنائي الأبعاد من الأنواع الأساسية-[[11 ، 12 ، 13 ، 14] ، [21 ، 22] person1 ، person2 ، person3 ، person4 ، person5 ، person6 ، person7 ، person8 ، person 9]-print-pint-tensional-dimensional type من النوع غير القاعدي-[[person10] ، [person11 ، person12] ، [person13 ، person14 ، person15]]. -صفيف ثنائي الأبعاد في الحالات الخاصة-[[] ، null ، [person16 ، null ، java.lang.object@ca0b6 ، 100]]-طباعة نتيجة الصفيف أحادي البعد إلى ملف--تنسيق الإخراج-10086 صحيح [[11 ، 12 ، 13 ، 14] ، [21 ، 21 ، 32 ، 32 ، 33]
ملف الإخراج:
يمكن ملاحظة أن فئة أدوات الطباعة لديها بالفعل القدرة على طباعة الأنواع الأساسية من المصفوفات أحادية البعد والمصفوفات متعددة الأبعاد. بشكل عام ، تعد فئة الأدوات أعلاه عملية تمامًا ، حتى لا تكتب التعليمات البرمجية يدويًا في كل مرة تريد فيها رؤية المحتويات في الصفيف. سيكون ذلك مزعجًا جدًا. فقط استخدم فئة أدوات الطباعة في المستقبل. كيف مريحة.
تعمل فئة الأدوات أعلاه بشكل جيد للغاية ، ولكن إذا كان هناك شرط: أعطيك صفيفًا (وربما حاويات أخرى) ، يمكنك إنشاء قائمة لي. إذن ماذا يجب أن نفعل؟ في الواقع ، لا يحصل arrays.aslist دائمًا على النتائج التي نتوقعها. على الرغم من أن Java5 يضيف الأدوية الجيرية ، إلا أنه يحتوي على قيود ولا يمكن أن يكون عامًا مثل قوالب C ++. إنه على وجه التحديد لأن هناك أنواعًا أساسية في Java. حتى لو كانت هناك آلية تغليف تلقائية ، فلا يمكن استخدامها مع الأداء الوطني. يجب أن يكون نوع المعلمة من نوع معين ، وليس نوعًا أساسيًا. هنا حل لك:
حزمة cn.zq.util ؛ استيراد java.lang.reflect.array ؛ استيراد java.util.arraylist ؛ استيراد java.util.arrays ؛ استيراد java.util.enumeration ؛ استيراد java.util.iterator ؛ استيراد java.util.list ؛ استيراد java.util.map ؛ مجموعة الفئة العامة {قائمة ثابتة عامة <؟> aslist (Object OBJ) {return convertToList (makeiterator (OBJ)) ؛ } static static <T> list <T> convertToList (iterator <T> iterator) {if (iterator == null) {return null ؛ } قائمة <T> list = new ArrayList <T> () ؛ بينما (iterator.hasnext ()) {list.add (iterator.next ()) ؛ } قائمة الإرجاع ؛ } suppressWarnings ({"rawtypes" ، "uncheded"}) iTerator ثابتة عامة <؟> makeiterator (Object OBJ) {if (obj exterator) {return (iterator <؟>) obj ؛ } if (obj == null) {return null ؛ } if (obj extryof map) {obj = ((map <؟ } iterator <؟> iterator = null ؛ if (obj extorlyof iterable) {iterator = ((itervable <؟>) obj) .iterator () ؛ } آخر إذا (obj.getClass (). isarray ()) {// object [] objs = (object []) obj ؛ // أو لا يمكن تحويل صفائف الأنواع البدائية مثل قائمة ArrayList هذه = ArrayList جديد (Array.getLength (OBJ)) ؛ لـ (int i = 0 ؛ i <array.getLength (obj) ؛ i ++) {list.add (array.get (obj ، i)) ؛ } iterator = list.iterator () ؛ } آخر إذا (obj extrealof enumeration) {iterator = new enumerationItiTerator ((reuumeration) obj) ؛ } آخر {iterator = arrays.aslist (obj) .iterator () ؛ } إرجاع التكرار ؛ } تعداد الفئة الثابتة العامة <T> يطرح ITerator <T> {التعداد الخاص <T> التعداد ؛ التعداد العام (التعداد <T> التعداد) {this.enumeration = التعداد ؛ } boolean public hasnext () {return enumeration.hasmoreElements () ؛ } public t next () {return enumeration.nextElement () ؛ } public void remove () {refl new UnsupportedOperationException () ؛ }}}رمز الاختبار:
حزمة cn.zq.array.reflect ؛ استيراد java.util.iterator ؛ استيراد java.util.list ؛ استيراد cn.zq.array.reflect.printtest.person ؛ استيراد cn.zq.util.collectionutils ؛ CollectionUtilstest {public static void main (string [] args) {system.out.println ("--- صفيف أحادي الأبعاد من النوع الأساسي-") ؛ int [] nums = {1 ، 3 ، 5 ، 7 ، 9} ؛ قائمة <؟> list = collectionUtils.aslist (nums) ؛ system.out.println (list) ؛ System.out.println ("-ليس من النوع الأساسي صفيف أحادي البعد-") ؛ الشخص [] الأشخاص = شخص جديد [] {new person () ، شخص جديد () ، شخص جديد () ،} ؛ قائمة <Person> personlist = (list <Person>) collectionUtils.aslist (أشخاص) ؛ system.out.println (personlist) ؛ system.out.println (personlist) ؛ system.out.println ("-iterator--") ؛ iterator <Person> iterator = personlist.iterator () ؛ قائمة <Person> personlist2 = (قائمة <Person>) CollectionUtils.Aslist (iterator) ؛ system.out.println (personlist2) ؛ }}الإخراج:
-صفيف أحادي الأبعاد من النوع-[1 ، 3 ، 5 ، 7 ، 9]-صفيف أحادي البعد أحادي البعد-
في مكتبة فئة حاوية Java ، يمكن تقسيمها إلى التجميع والخريطة والمصفوفة. نظرًا لأن Iterator (وتعداد الواجهة القديمة المبكرة) هو الواجهة العامة لجميع الحاويات وواجهة التجميع من Iterfable (سيعيد Iterator لهذه الواجهة إلى مؤلف) ، تتم معالجة هذه المواقف واحدة تلو الأخرى في طريقة Makeiterator. بالنسبة لأنواع الخريطة ، يجب استدعاء طريقة الإدخال () فقط. بالنسبة للفئات التي تنفذ الواجهة المطلقة (بما في ذلك المجموعة) ، اتصل بـ ITerator () للحصول على كائن Iterator مباشرة. لأنواع التعداد ، استخدم requerationiTerator المحول للتكيف. بالنسبة للمصفوفات ، استخدم انعكاس الصفيف لاجتياز الصفيف في ArrayList ، واتصل بالطريقة Assist.Aslist () لإنشاء قائمة لأنواع أخرى. يوفر CollectionUtils أيضًا بعض الطرق الأخرى للتحويل ، ويمكنك إضافة الطرق التي تحتاجها حسب الحاجة.
ملخص: يوفر انعكاس المصفوفة طرقًا أكثر ملاءمة ومرنة للتصميمات التي قد تظهر فيها المصفوفات ، حتى لا تكتب المزيد من بيانات الحكم المزعجة. تدفع هذه المرونة سعر الأداء ، وليس من الضروري حقًا استخدام انعكاس الصفيف عندما لا تكون هناك حاجة إلى انعكاس الصفيف على الإطلاق. ما إذا كان لاستخدام انعكاسات الصفيف يختلف في التطوير الفعلي. اختر ما إذا كنت تستخدم انعكاسات الصفيف وفقًا للاحتياجات. أفضل طريقة هي استكشاف الطريق من خلال التدريب ، والكتابة بالطريقة التي تفكر بها ، والتحسن باستمرار في الممارسة.