عندما بدأت تعلم لغة Java لأول مرة، كان من الصعب جدًا فهم معنى الانعكاس.
بعض الكتب، حتى الكلاسيكية منها، تشرح الأشياء بطريقة تجعل الناس يشعرون بالارتباك. ربما أنا غبي جدًا.
علاوة على ذلك، يقال عبر الإنترنت أن آلية التفكير يجب استخدامها بشكل متكرر عند تعلم أطر العمل في المستقبل، مما يجعل الناس يشعرون دائمًا بعدم الارتياح قليلاً.
لقد شاهدت بالصدفة بعض الفصول ومقاطع الفيديو التي تشرح التأمل، وأعتقد أنني أستطيع فهم الأمر بشكل أفضل قليلاً.
الآن قررت أن أعمل بجد، وأقرأ وأكتب في نفس الوقت، وأسجل بعض المحتويات والعمليات الرئيسية هنا.
أعتقد أنه بالنسبة لشخص غبي مثلي، ربما تكون أفضل طريقة للتعلم هي التكرار
عندما أواجه شيئًا لا أفهمه، أتوقف وأتعلمه مرة أخرى، وعلى الرغم من أن ذلك يضيع الكثير من الوقت، إلا أنه يؤثر علي أيضًا.
ما أفهمه هو: ما يسمى بالانعكاس هو استعادة المعلومات الكاملة للفئة بناءً على كائن تم إنشاء مثيل له بالفعل.
على الأقل بالنسبة لي، أعتقد أن الفائدة التي يجلبها لي هي أنه يسمح لي بفهم التوجه الشيئي من الأسفل إلى الأعلى.
x_x أنا هنا أكره تلك الرؤوس السميكة مرة أخرى، لقد قتلوا كل خلايا دماغي.
فئة الطبقةإذا كنت ترغب في إكمال التفكير، فيجب عليك فهم فئة الفصل
مثال 1: الحصول على اسم الحزمة واسم الفئة من خلال الكائناختبار الصف {
}
عرض الطبقة العامة {
public static void main(String[] args) {
اختبار ر = اختبار جديد ()؛
System.out.println(t.getClass());
System.out.println(t.getClass().getName());
}
}
نتائج التجميع هي كما يلي، فقط انتبه إلى كيفية تجميع الحزمة.
يتم توريث طريقة getClass() هنا من فئة الكائن بشكل افتراضي.
في Java، فئة الكائن هي الفئة الأصلية لجميع الفئات، وبالمثل، فإن الكائنات التي تم إنشاء مثيل لها في جميع الفئات هي أيضًا مثيلات لفئة الفئة.
ولذلك، فإن هذا سوف يشمل مفاهيم التحول التصاعدي والتحول التنازلي
ستتبع الأدوية العامة هنا أيضًا بسبب عدم أمان القوالب الهابطة.
(ولكن ما أريد قوله هو أن التصميم العام هنا مبهر للغاية! اللعنة، تصميم بناء الجملة لجافا بأكملها مبهر أيضًا، ومثير للاشمئزاز للغاية !!!)
المثال 2: إنشاء مثيل لفئة Classنظرًا لأن فئة Class لا تحتوي على مُنشئ، فإن طريقة إنشاء فئة Class تكون خاصة بعض الشيء. هناك ثلاث طرق:
كائن.getClass()}
عرض الطبقة العامة {
public static void main(String[] args) {
// الطريقة الأولى:
اختبار ر = اختبار جديد ()؛
Class<? Extends Test> c1 = t.getClass();
System.out.println(c1);
// الطريقة الثانية:
// لتجنب الخصوصية، لا يتم استخدام فئة الاختبار هنا، ولكن يتم استخدام فئة السلسلة في مكتبة جافا.
Class<String> c2 = String.class;
System.out.println(c2);
// الطريقة الثالثة:
// طريقة forName () ستطرح استثناءً
Class<?> c3 = null;
يحاول {
c3 = Class.forName("اختبار");
} التقاط (ClassNotFoundException e) {
printStackTrace();
}
System.out.println(c3);
}
}
توجد طريقة في فئة Class تسمى newInstance()، والتي يمكن استخدامها لإنشاء مثيل جديد لكائن فئة Class
كيف أقول ذلك؟ المحتوى الموجود في كائن الفئة هو الفئة المنعكسة. نحتاج إلى إنشاء مثيل جديد (كائن جديد) لتلك الفئة.
مثال 3: إنشاء كائن بدون معلمات فئة الفئة // أنشئ مرجعًا لسلسلة
سلسلة ق = فارغة؛
يحاول {
// قم بإسقاط الكائن الذي تم إنشاؤه إلى فئة السلسلة
// طريقة newInstance () ستطرح استثناءً
s = (String) c.newInstance();
} قبض على (InstantiationException e) {
printStackTrace();
} قبض على (IllegalAccessException e) {
printStackTrace();
}
System.out.println("طول السلسلة:" + s.length());
}
}
يؤدي هذا إلى إنشاء كائن جديد في نموذج بدون معلمات، تمامًا كما هو الحال في الوضع العادي
إن إنشاء كائن جديد من خلال المُنشئ بدون وسيطة هو نفسه
نحن نعلم أنه بالإضافة إلى المُنشئات التي لا تحتوي على معلمات، هناك أيضًا مُنشئات ذات معلمات في الفصل.
فكيف يتم بناء الكائنات في شكل معلمات في الانعكاس؟ واصل القراءة
مثال 4: كائن تم إنشاؤه بمعلمات من فئة Class عرض الطبقة العامة {
// تطرح الطرق التالية عددًا كبيرًا جدًا من الاستثناءات، من أجل ضغط التعليمات البرمجية، يتم طرحها مباشرة إلى الجهاز الظاهري هنا.
public static void main(String[] args) يطرح الاستثناء {
Class<?> c = null;
يحاول {
c = Class.forName("java.lang.String");
} التقاط (ClassNotFoundException e) {
printStackTrace();
}
char[] ch = {'h','e','l','l','o'};
سلسلة ق = فارغة؛
// احصل على المُنشئ ذي المعلمات لكائن الفئة. تتم كتابة المعلمات الموجودة بين قوسين على النحو التالي: type.class
Constructor<?> con = c.getConstructor(char[].class);
// استخدم طريقة البناء هذه لإنشاء كائن سلسلة جديد، والمعلمة عبارة عن صفيف char
s = (String) con.newInstance(ch);
System.out.println("سلسلة تم إنشاؤها:" + s);
}
}
ما زلنا نستخدم فئة السلسلة كمثال، لأن فئة السلسلة تستخدم في كثير من الأحيان وأسهل في الفهم.
ما يجب ملاحظته هنا هو أنه يجب الحصول على المُنشئ باستخدام طريقة getConstructor()
أما نوع المعلمة فهو: original type.class
نقطة أخرى هي أنه سواء كانت تحتوي على معلمات أو لا تحتوي على معلمات، فإن طريقة البناء المستخدمة هنا يجب أن تكون موجودة في الفئة الأصلية.
إذًا، كيف يمكننا معرفة المعلومات التفصيلية مثل طريقة البناء والطريقة العادية والفئة الأصلية الموروثة وما إلى ذلك في الفئة الأصلية؟ واصل القراءة
الحصول على هيكل الفصلللحصول على بنية الفصل من خلال الانعكاس، نحتاج إلى استيراد حزمة جديدة java.lang.reflect
مثال 5: الحصول على مُنشئ الفصل عرض الطبقة العامة {
// تطرح الطرق التالية عددًا كبيرًا جدًا من الاستثناءات، من أجل ضغط التعليمات البرمجية، يتم طرحها مباشرة إلى الجهاز الظاهري هنا.
public static void main(String[] args) يطرح الاستثناء {
Class<?> c = null;
يحاول {
c = Class.forName("java.lang.Boolean");
} التقاط (ClassNotFoundException e) {
printStackTrace();
}
// تقوم طريقة getConstructors () هنا بإرجاع مصفوفة منشئ
Constructor<?>[] cons = c.getConstructors();
// يمكنك كتابة طريقة الطباعة بنفسك، من أجل الراحة، أستخدم Arrays.toString() للقيام بذلك.
System.out.println(Arrays.toString(cons));
}
}
عرض الطبقة العامة {
public static void main(String[] args) يطرح الاستثناء {
Class<?> c = null;
يحاول {
c = Class.forName("java.lang.Boolean");
} التقاط (ClassNotFoundException e) {
printStackTrace();
}
Class<?>[] in = c.getInterfaces();
System.out.println(Arrays.toString(in));
}
}
عرض الطبقة العامة {
public static void main(String[] args) يطرح الاستثناء {
Class<?> c = null;
يحاول {
c = Class.forName("java.lang.Boolean");
} التقاط (ClassNotFoundException e) {
printStackTrace();
}
الطريقة[] m = c.getMethods();
// حسنًا، هذه المرة سأكون رحيمًا وأكتب قائمة مطبوعة.
لـ (int i = 0; i < m.length; i++) {
System.out.println(m[i]);
}
}
}
شخص الصف {
اسم سلسلة خاصة؛
عمر خاص؛
}
عرض الطبقة العامة {
public static void main(String[] args) يطرح الاستثناء {
Class<?> c = null;
يحاول {
ج = Class.forName("شخص");
} التقاط (ClassNotFoundException e) {
printStackTrace();
}
Field[] f = c.getDeclaredFields();
لـ (int i = 0; i < f.length; i++) {
System.out.println(f[i]);
}
}
}
يمكن للأسلوب getDeclaredFielsd () الحصول على جميع الخصائص، ويمكن لـ getFields () الحصول على الخصائص العامة فقط.
مثال 10: احصل على قيمة السمة في هذه الفئة شخص الصف {
اسم السلسلة العامة؛
عمر خاص؛
شخص عام (اسم السلسلة، العمر int) {
this.name = name;
this.age = age;
}
}
عرض الطبقة العامة {
public static void main(String[] args) يطرح الاستثناء {
Person p = new Person("zhangsan",12);
Class<?> c = p.getClass();
// احصل على قيمة السمة العامة
الحقل f1 = c.getField("name");
يشير //get(p) إلى قيمة الكائن التي سيتم الحصول عليها
String str = (String) f1.get(p);
System.out.println("الاسم:" + str);
// احصل على قيمة السمة الخاصة
الحقل f2 = c.getDeclaredField("age");
// العمر هو ملكية خاصة، لذا اضبط التحقق الأمني على "صحيح".
f2.setAccessible(true);
int age = (int) f2.get(p);
System.out.println("العمر: " + العمر);
}
}
بصراحة، لم أجد أي معرفة في جافا يمكن أن تعمي عيني المصنوعة من التيتانيوم.
في كل مرة، يجب أن أكتب مجموعة من الصيغ المملة لتنفيذ أداة ما، وإلا سأضطر إلى استدعاء واجهة برمجة التطبيقات (API) بشكل يائس ورمي الاستثناءات بشكل يائس.
جعل التعليمات البرمجية غير المضغوطة بدرجة كافية تصبح مرهقة
إذا كنت أحب لغة ما، فإن خصائصها الخاصة يجب أن تثير إعجابي قبل أن أتمكن من استخدامها لصنع شيء ما.
من الواضح أن Java لا تجعلني سعيدًا، ربما يضطر العديد من المبرمجين مثلي إلى استخدام Java.
فقط لإرضاء قلبي المبرمج الوحيد، تابع القراءة أدناه
مثال تطبيق الانعكاس 11: تعديل السمات من خلال الانعكاس شخص الصف {
اسم سلسلة خاصة؛
شخص عام (اسم السلسلة) {
this.name = name;
}
سلسلة عامة إلى سلسلة () {
إرجاع "الاسم:" + this.name;
}
}
عرض الطبقة العامة {
public static void main(String[] args) يطرح الاستثناء {
Person p = new Person("王二狗");
System.out.println(ع);
Class<?> c = p.getClass();
// تحديد الخصائص المراد تعديلها
الحقل f = c.getDeclaredField("name");
f.setAccessible(true);
// تعديل الخصائص وتمرير الكائن والقيمة المراد تعيينها
f.set(p, "تشانغ إردان");
System.out.println(ع);
}
}
شخص الصف {
طباعة باطلة عامة (int i) {
System.out.println("أنا أكتب الأرقام:" + i);
}
قول الفراغ الثابت العام (سلسلة str) {
System.out.println("أنا أقول:" + str);
}
}
عرض الطبقة العامة {
public static void main(String[] args) يطرح الاستثناء {
الشخص ع = شخص جديد ()؛
Class<?> c = p.getClass();
// تحتاج طريقة getMethod () إلى تمرير اسم الطريقة ونوع المعلمة
الطريقة m1 = c.getMethod("print"، int.class);
// استدعاء () يعني الاتصال ويحتاج إلى تمرير الكائنات والمعلمات
m1.invoc(p, 10);
الطريقة m2 = c.getMethod("say"، String.class);
// القيمة الخالية هنا تعني عدم استدعاء الكائن، أي طريقة ثابتة
m2.invoc(null, "أختك");
}
}
فيما يلي عرض توضيحي للطريقة ذات المعلمات العادية والطريقة الثابتة
الآن بعد أن تمت كتابة جميع المعلمات، أصبحت المعلمات التي لا تحتوي على معلمات أكثر بساطة. ما عليك سوى تمرير الكائن مباشرة.
مثال 13: التعامل مع المصفوفات من خلال الانعكاس عرض الطبقة العامة {
public static void main(String[] args) يطرح الاستثناء {
int[] arr = {1,2,3,4,5};
Class<?> c = arr.getClass().getComponentType();
System.out.println("نوع الصفيف:" + c.getName());
int len = Array.getLength(arr);
System.out.println("طول الصفيف:" + len);
System.out.print("اجتياز المصفوفة:");
لـ (int i = 0; i < len; i++) {
System.out.print(Array.get(arr, i) + " ");
}
System.out.println();
// تعديل المصفوفة
System.out.println("العنصر الأول قبل التعديل:" + Array.get(arr, 0));
Array.set(arr, 0, 3);
System.out.println("العنصر الأول المعدل:" + Array.get(arr, 0));
}
}
هذا كل شيء في الوقت الحالي، يتضمن الكتاب الذي قرأته أيضًا تطبيق الانعكاس في وضع المصنع.
إنه ليس أكثر من استبداله بالطريقة forName(). ليس هناك الكثير مما يمكن قوله.
أنا مبتدئ في جافا وأكره بناء الجملة وتصميم جافا المثير للاشمئزاز.
هذا كله من أجل Android، لوضع الأساس والتكيف مع العمل المستقبلي.