מדריך להשתקפות ג'אווה

1. סקירה כללית

במאמר זה נחקור את השתקפות Java, המאפשרת לנו לבדוק או / ולשנות תכונות זמן ריצה של מחלקות, ממשקים, שדות ושיטות. זה שימושי במיוחד כאשר איננו יודעים את שמותיהם בזמן הקומפילציה.

בנוסף, אנו יכולים ליצור עצמים חדשים, להפעיל שיטות ולקבל או להגדיר ערכי שדה באמצעות השתקפות.

2. הגדרת פרויקט

כדי להשתמש בהשתקפות Java, איננו צריכים לכלול צנצנות מיוחדות, כל תצורה מיוחדת, או תלות של Maven. ה- JDK נשלח עם קבוצה של כיתות המאוגדות ב java.lang.reflect חבילה במיוחד למטרה זו.

אז כל שעלינו לעשות הוא לבצע את הייבוא ​​הבא לקוד שלנו:

ייבא java.lang.reflect. *;

ואנחנו טובים ללכת.

כדי לקבל גישה למידע בכיתה, בשיטה ובשטח של מקרה שאנחנו מכנים getClass שיטה המחזירה את ייצוג המחזור בזמן הריצה של האובייקט. השבים מעמד האובייקט מספק שיטות לגישה למידע על מחלקה.

3. דוגמה פשוטה

כדי להרטיב את הרגליים, אנו נסתכל על דוגמה בסיסית מאוד הבודקת את השדות של אובייקט Java פשוט בזמן הריצה.

בואו ניצור פשוט אדם כיתה עם בלבד שֵׁם ו גיל שדות וללא שיטות בכלל. הנה שיעור האדם:

אדם בכיתה ציבורית {פרטי שם מחרוזת; גיל פרטי פרטי; }

כעת נשתמש בהשתקפות Java כדי לגלות את שמות כל שדות המחלקה הזו. כדי להעריך את כוח ההשתקפות, נבנה א אדם התנגד והשתמש באובייקט כסוג ההפניה:

@ מבחן חלל ציבורי givenObject_whenGetsFieldNamesAtRuntime_thenCorrect () {אובייקט אדם = אדם חדש (); שדה [] שדות = person.getClass (). GetDeclaredFields (); רשימת actualFieldNames = getFieldNames (שדות); assertTrue (Arrays.asList ("שם", "גיל") .containsAll (actualFieldNames)); }

בדיקה זו מראה לנו שאנחנו מסוגלים להשיג מגוון של Field חפצים משלנו אדם אובייקט, גם אם ההתייחסות לאובייקט היא סוג אב של אובייקט זה.

בדוגמה שלעיל התעניינו רק בשמות אותם שדות, אך ניתן לעשות הרבה יותר ואנחנו נראה דוגמאות נוספות לכך בחלקים הבאים.

שימו לב כיצד אנו משתמשים בשיטת עוזר לחילוץ שמות השדות בפועל, זהו קוד בסיסי מאוד:

רשימה סטטית פרטית getFieldNames (שדות [] שדות) {רשימה fieldNames = ArrayList חדש (); עבור (שדה שדה: שדות) fieldNames.add (field.getName ()); השדה fieldNames; }

4. מקרי שימוש בהשתקפות Java

לפני שנמשיך לתכונות השונות של השתקפות Java, נדון בכמה מהשימושים הנפוצים שאנו עשויים למצוא עבורו. השתקפות ג'אווה חזקה במיוחד ויכולה להיות שימושית במספר דרכים.

למשל, במקרים רבים יש לנו מוסכמת שמות לטבלאות מסדי נתונים. אנו עשויים לבחור להוסיף עקביות על ידי תיקון מראש עם שמות הטבלאות שלנו tbl_, כך שקוראים לטבלה עם נתוני סטודנטים tbl_student_data.

במקרים כאלה, אנו עשויים למנות את אובייקט Java המחזיק בנתוני התלמידים בשם סטוּדֶנט אוֹ StudentData. ואז באמצעות פרדיגמת CRUD, יש לנו נקודת כניסה אחת לכל פעולה כזו לִיצוֹר הפעולות מקבלות רק לְהִתְנַגֵד פָּרָמֶטֶר.

לאחר מכן אנו משתמשים בבבואה כדי לאחזר את שם האובייקט ושמות השדות. בשלב זה אנו יכולים למפות נתונים אלה לטבלת DB ולהקצות את ערכי שדה האובייקט לשמות השדות המתאימים של DB.

5. בדיקת שיעורי Java

בחלק זה נחקור את המרכיב הבסיסי ביותר בממשק ה- API של השתקפות Java. אובייקטים של מחלקת Java, כפי שהזכרנו קודם, נותנים לנו גישה לפרטים הפנימיים של כל אובייקט.

אנו הולכים לבחון פרטים פנימיים כגון שם מחלקה של אובייקט, שינויים, שדות, שיטות, ממשקים מיושמים וכו '.

5.1. מתכונן

כדי לקבל אחיזה איתנה ב- API ההשתקפות, כפי שהוא מוחל על שיעורי Java ויש לנו דוגמאות עם מגוון, ניצור תקציר בעל חיים כיתה המיישמת את אֲכִילָה מִמְשָׁק. ממשק זה מגדיר את התנהגות האכילה של כל בטון בעל חיים אובייקט שאנחנו יוצרים.

אז ראשית, הנה אֲכִילָה מִמְשָׁק:

ממשק ציבורי אכילה {מחרוזת אוכלת (); }

ואז הבטון בעל חיים יישום ה- אֲכִילָה מִמְשָׁק:

שיעור מופשט ציבורי מכלי בעלי חיים אכילה {מחרוזת סטטית ציבורית CATEGORY = "ביתית"; שם מחרוזת פרטי; מופשט מוגן מחרוזת getSound (); // קונסטרוקטור, גטרים סטנדרטיים וקובעים הושמטו}

בואו ניצור גם ממשק נוסף שנקרא תְנוּעָה המתאר כיצד חיה נעה:

ממשק ציבורי Locomotion {String getLocomotion (); }

כעת ניצור מעמד קונקרטי שנקרא עֵז שמתארך בעל חיים ומכשירים תְנוּעָה. מאז יישומי הסופר-קלאס אֲכִילָה, עֵז יהיה עליה ליישם גם את השיטות של ממשק זה:

מעמד ציבורי עז מרחיבה מכשירים בעלי חיים תנועה {@Override מוגן מחרוזת getSound () {להחזיר "bleat"; } @Override מחרוזת ציבורית getLocomotion () {להחזיר "הליכות"; } @Override ציבור מחרוזת אוכלת () {להחזיר "דשא"; } // בונה הושמט}

מנקודה זו ואילך, נשתמש בהשתקפות ג'אווה לבדיקת היבטים של אובייקטים ג'אווה המופיעים בשיעורים ובממשקים שלמעלה.

5.2. שמות כיתות

נתחיל בקבלת שם האובייקט מה- מעמד:

@ מבחן בטל פומבי givenObject_whenGetsClassName_thenCorrect () {אובייקט עז = עז חדשה ("עז"); קלאס קלאסי = goat.getClass (); assertEquals ("עז", clazz.getSimpleName ()); assertEquals ("com.baeldung.reflection.Goat", clazz.getName ()); assertEquals ("com.baeldung.reflection.Goat", clazz.getCanonicalName ()); }

שים לב שה- getSimpleName שיטה של מעמד מחזיר את השם הבסיסי של האובייקט כפי שהוא יופיע בהצהרה שלו. ואז שתי השיטות האחרות מחזירות את שם הכיתה המלא, כולל הצהרת החבילה.

בואו נראה גם כיצד אנו יכולים ליצור אובייקט של ה- עֵז בכיתה אם אנו יודעים רק את שם הכיתה המלא שלה:

@Test ציבור בטל givenClassName_whenCreatesObject_thenCorrect () {Class clazz = Class.forName ("com.baeldung.reflection.Goat"); assertEquals ("עז", clazz.getSimpleName ()); assertEquals ("com.baeldung.reflection.Goat", clazz.getName ()); assertEquals ("com.baeldung.reflection.Goat", clazz.getCanonicalName ()); }

שימו לב שהשם שאנחנו מעבירים לסטטי forName השיטה צריכה לכלול את פרטי החבילה. אחרת נקבל א ClassNotFoundException.

5.3. משנים כיתות

אנו יכולים לקבוע את השינויים המשמשים בשיעור על ידי קריאת ה- getModifiers שיטה המחזירה מספר שלם. כל שינוי הוא ביט דגל אשר מוגדר או מנוקה.

ה java.lang.reflect.Modifier class מציע שיטות סטטיות המנתחות את המוחזר מספר שלם לנוכחות או היעדרות של שינוי ספציפי.

בואו נאשר את השינויים של חלק מהשיעורים שהגדרנו לעיל:

@Test ציבור בטל givenClass_whenRecognisesModifiers_thenCorrect () {Class goatClass = Class.forName ("com.baeldung.reflection.Goat"); Class animalClass = Class.forName ("com.baeldung.reflection.Animal"); int goatMods = goatClass.getModifiers (); int animalMods = animalClass.getModifiers (); assertTrue (Modifier.isPublic (goatMods)); assertTrue (Modifier.isAbstract (animalMods)); assertTrue (Modifier.isPublic (animalMods)); }

אנו מסוגלים לבדוק מהכלים מכל סוג שנמצא בצנצנת הספרייה שאנו מייבאים לפרויקט שלנו.

ברוב המקרים, ייתכן שנצטרך להשתמש ב- forName גישה ולא המיידיות המלאה מכיוון שזה יהיה תהליך יקר במקרה של שיעורים כבדים בזיכרון.

5.4. מידע על החבילה

באמצעות השתקפות Java אנו יכולים גם לקבל מידע על החבילה של כל מחלקה או אובייקט. נתונים אלה מקובצים בתוך ה- חֲבִילָה כיתה אשר מוחזרת בשיחה אל getPackage שיטה על אובייקט הכיתה.

בואו נבצע בדיקה לאחזור שם החבילה:

@ מבחן ציבורי בטל givenClass_whenGetsPackageInfo_thenCorrect () {עז עז = עז חדשה ("עז"); Class goatClass = goat.getClass (); חבילה pkg = goatClass.getPackage (); assertEquals ("com.baeldung.reflection", pkg.getName ()); }

5.5. סופר קלאס

אנו מצליחים להשיג את הסופר-קלאס של כל מחלקת Java באמצעות השתקפות Java.

במקרים רבים, במיוחד בעת שימוש בשיעורי ספריה או בכיתות מובנות של ג'אווה, ייתכן שלא נדע לפני כן את הסופר-קלאס של אובייקט בו אנו משתמשים, סעיף משנה זה יראה כיצד להשיג מידע זה.

אז בואו נמשיך ונקבע את מעמד העל של עֵז. בנוסף, אנו גם מראים זאת מיתר הכיתה היא תת-מחלקה של java.lang. אובייקט מעמד:

@ מבחן בטל פומבי givenClass_whenGetsSuperClass_thenCorrect () {עז עז = עז חדשה ("עז"); מחרוזת str = "כל מחרוזת"; Class goatClass = goat.getClass (); Class goatSuperClass = goatClass.getSuperclass (); assertEquals ("בעלי חיים", goatSuperClass.getSimpleName ()); assertEquals ("Object", str.getClass (). getSuperclass (). getSimpleName ()); }

5.6. ממשקים מיושמים

באמצעות השתקפות ג'אווה, אנו גם מסוגלים קבל את רשימת הממשקים המיושמים על ידי מחלקה מסוימת.

בואו נאחזר את סוגי המחלקות של הממשקים המיושמים על ידי ה- עֵז הכיתה וה בעל חיים שיעור מופשט:

@Test הציבור בטל givenClass_whenGetsImplementedInterfaces_thenCorrect () {Class goatClass = Class.forName ("com.baeldung.reflection.Goat"); Class animalClass = Class.forName ("com.baeldung.reflection.Animal"); מחלקה [] goatInterfaces = goatClass.getInterfaces (); Class [] animalInterfaces = animalClass.getInterfaces (); assertEquals (1, goatInterfaces.length); assertEquals (1, animalInterfaces.length); assertEquals ("תנועה", goatInterfaces [0] .getSimpleName ()); assertEquals ("אכילה", ממשק בעלי חיים [0] .getSimpleName ()); }

שימו לב מהטענות שכל מחלקה מיישמת ממשק יחיד בלבד. בבדיקת שמות הממשקים הללו אנו מגלים זאת עֵז מכשירים תְנוּעָה ו בעל חיים מכשירים אֲכִילָה, בדיוק כפי שהוא מופיע בקוד שלנו.

אולי הבחנת בכך עֵז הוא תת-מחלקה של המעמד המופשט בעל חיים ומיישם את שיטת הממשק אוכל (), לאחר מכן, עֵז מיישם גם את אֲכִילָה מִמְשָׁק.

לכן ראוי לציין כי רק אותם ממשקים שהכיתה מצהירה עליהם במפורש כמיושמים עם ה- מכשירים מילת המפתח מופיעה במערך המוחזר.

אז גם אם מחלקה מיישמת שיטות ממשק מכיוון שהמעמד העל שלה מיישם את הממשק הזה, אך מחלקת המשנה אינה מכריזה ישירות על ממשק זה עם מכשירים מילת מפתח, אז ממשק זה לא יופיע במערך הממשקים.

5.7. קונסטרוקטורים, שיטות ושדות

בעזרת השתקפות ג'אווה, אנו מסוגלים לבדוק את הבונים של מעמד כל אובייקט כמו גם שיטות ושדות.

בהמשך, נוכל לראות בדיקות מעמיקות יותר על כל אחד ממרכיבי הכיתה, אך לעת עתה, מספיק רק לקבל את שמותיהם ולהשוות אותם למה שאנחנו מצפים.

בואו נראה איך להשיג את הבנאי של ה- עֵז מעמד:

@Test הציבור בטל givenClass_whenGetsConstructor_thenCorrect () {Class goatClass = Class.forName ("com.baeldung.reflection.Goat"); קונסטרוקטור [] בונים = goatClass.getConstructors (); assertEquals (1, constructors.length); assertEquals ("com.baeldung.reflection.Goat", בונים [0] .getName ()); }

אנחנו יכולים גם לבדוק את השדות של בעל חיים כיתה ככה:

@Test הציבור בטל givenClass_whenGetsFields_thenCorrect () {Class animalClass = Class.forName ("com.baeldung.reflection.Animal"); שדה [] שדות = animalClass.getDeclaredFields (); רשימת actualFields = getFieldNames (שדות); assertEquals (2, actualFields.size ()); assertTrue (actualFields.containsAll (Arrays.asList ("שם", "CATEGORY"))); }

בדיוק כמו שאנחנו יכולים לבדוק את השיטות של בעל חיים מעמד:

@Test הציבור בטל givenClass_whenGetsMethods_thenCorrect () {Class animalClass = Class.forName ("com.baeldung.reflection.Animal"); שיטה [] שיטות = animalClass.getDeclaredMethods (); רשימת actualMethods = getMethodNames (שיטות); assertEquals (4, actualMethods.size ()); assertTrue (actualMethods.containsAll (Arrays.asList ("getName", "setName", "getSound"))); }

בדיוק כמו getFieldNames, הוספנו שיטת עוזר לאחזור שמות שיטות ממערך של שיטה חפצים:

רשימה סטטית פרטית getMethodNames (שיטות [] שיטות) {List methodNames = ArrayList new (); עבור (שיטת שיטה: שיטות) methodNames.add (method.getName ()); שיטת החזרה שמות; }

6. בדיקת קונסטרוקטורים

עם השתקפות Java, אנחנו יכולים לבדוק בונים מכל כיתה ואפילו ליצור אובייקטים בכיתה בזמן ריצה. זה מתאפשר על ידי java.lang.reflect.Constructor מעמד.

מוקדם יותר בדקנו רק כיצד להשיג את מערך בַּנַאִי חפצים, מהם הצלחנו להשיג את שמות הבנאים.

בחלק זה נתמקד כיצד לאחזר בונים ספציפיים. בג'אווה, כידוע, אין שני בונים של מחלקה חולקים בדיוק את אותה חתימת שיטה. אז נשתמש בייחודיות זו כדי להשיג בנאי אחד מרבים.

כדי להעריך את התכונות של הכיתה הזו, ניצור ציפור תת מחלקה של בעל חיים עם שלושה בונים. לא ניישם תְנוּעָה כדי שנוכל לציין התנהגות זו באמצעות טיעון קונסטרוקטור, כדי להוסיף עוד יותר מגוון:

מעמד ציבורי ציפור מרחיבה בעלי חיים {טיולים בוליאניים פרטיים; ציפור ציבורית () {סופר ("ציפור"); } ציפור ציבורית (שם מחרוזת, הליכות בוליאניות) {סופר (שם); setWalks (הליכות); } ציפור ציבורית (שם מחרוזת) {סופר (שם); } טיולים בוליאניים ציבוריים () {טיולים חוזרים; } // קובעי סטנדרטיים ושיטות שנדרסו}

בואו נאשר באמצעות השתקפות כי בכיתה זו יש שלושה בונים:

@Test ציבור בטל givenClass_whenGetsAllConstructors_thenCorrect () {Class birdClass = Class.forName ("com.baeldung.reflection.Bird"); קונסטרוקטור [] בונים = birdClass.getConstructors (); assertEquals (3, constructors.length); }

לאחר מכן, נחזיר כל קונסטרוקטור ל- ציפור מחלקה על ידי העברת סוגי מחלקות הפרמטר של הקונסטרוקטור בסדר מוצהר:

@Test הציבור בטל givenClass_whenGetsEachConstructorByParamTypes_thenCorrect () {Class birdClass = Class.forName ("com.baeldung.reflection.Bird"); Constructor cons1 = birdClass.getConstructor (); Constructor cons2 = birdClass.getConstructor (String.class); Constructor cons3 = birdClass.getConstructor (String.class, boolean.class); }

אין צורך בקביעה שכן כאשר בנאי עם סוגי פרמטרים מסוימים בסדר הנתון לא קיים, נקבל NoSuchMethodException והמבחן ייכשל אוטומטית.

במבחן האחרון נראה כיצד ליצור עצמים בזמן ריצה תוך אספקת הפרמטרים שלהם:

@Test הציבור בטל givenClass_whenInstantiatesObjectsAtRuntime_thenCorrect () {Class birdClass = Class.forName ("com.baeldung.reflection.Bird"); Constructor cons1 = birdClass.getConstructor (); Constructor cons2 = birdClass.getConstructor (String.class); Constructor cons3 = birdClass.getConstructor (String.class, boolean.class); ציפור ציפורים 1 = (ציפור) חסות 1. newInstance (); ציפור ציפורים 2 = (ציפור) חסר 2. newInstance ("ציפור אורגת"); ציפור ציפור 3 = (ציפור) חסר 3. newInstance ("יונה", נכון); assertEquals ("ציפור", bird1.getName ()); assertEquals ("ציפור אורגת", bird2.getName ()); assertEquals ("יונה", bird3.getName ()); assertFalse (bird1.walks ()); assertTrue (bird3.walks ()); }

אנו מיישרים חפצים בכיתה על ידי קריאה ל newInstance שיטה של בַּנַאִי בכיתה והעברת הפרמטרים הנדרשים בסדר מוצהר. לאחר מכן נזרק את התוצאה לסוג הנדרש.

אפשר גם להתקשר לבנאי ברירת המחדל באמצעות ה- Class.newInstance () שיטה. עם זאת, שיטה זו הוצאה משימוש מאז Java 9, ואנחנו לא צריכים להשתמש בה בפרויקטים של Java מודרניים.

ל ציפור 1, אנו משתמשים בבנאי ברירת המחדל שממנו שלנו ציפור קוד, מגדיר את השם באופן אוטומטי לציפור ואנו מאשרים זאת באמצעות בדיקה.

לאחר מכן אנו מיישרים ציפור 2 עם שם ובדיקה בלבד, זכור שכאשר איננו מגדירים התנהגות תנועה שכן ברירת המחדל היא שקר, כפי שנראה בשתי הקבוצות האחרונות.

7. בדיקת שדות

בעבר בדקנו רק את שמות השדות, בחלק זה, אנו נראה כיצדלהשיג ולהגדיר את הערכים שלהם בזמן הריצה.

ישנן שתי שיטות עיקריות המשמשות לבדיקת שדות בכיתה בזמן הריצה: getFields () ו getField (fieldName).

ה getFields () השיטה מחזירה את כל השדות הציבוריים הנגישים של הכיתה הנדונה. זה יחזיר את כל השדות הציבוריים בכיתה וגם בכל מחלקות העל.

לדוגמא, כאשר אנו קוראים לשיטה זו ב- ציפור בכיתה, נקבל רק את קטגוריה שדה של מעמד העל שלו, בעל חיים, מאז ציפור עצמו אינו מכריז על שדות ציבוריים כלשהם:

@Test הציבור בטל givenClass_whenGetsPublicFields_thenCorrect () {Class birdClass = Class.forName ("com.baeldung.reflection.Bird"); שדה [] שדות = birdClass.getFields (); assertEquals (1, fields.length); assertEquals ("CATEGORY", שדות [0] .getName ()); }

לשיטה זו יש גם גרסה הנקראת getField שמחזיר רק אחד שדה התנגד על ידי לקיחת שם השדה:

@Test הציבור בטל givenClass_whenGetsPublicFieldByName_thenCorrect () {Class birdClass = Class.forName ("com.baeldung.reflection.Bird"); שדה שדה = birdClass.getField ("CATEGORY"); assertEquals ("CATEGORY", field.getName ()); }

איננו יכולים לגשת לשדות פרטיים המוצהרים בכיתות-על ואינם מוכרזים בכיתת הילדים. זו הסיבה שאנחנו לא מסוגלים לגשת ל- שֵׁם שדה.

עם זאת, אנו יכולים לבדוק שדות פרטיים שהוכרזו בכיתה בה אנו עוסקים על ידי קריאה ל getDeclaredFields שיטה:

@Test הציבור בטל givenClass_whenGetsDeclaredFields_thenCorrect () {Class birdClass = Class.forName ("com.baeldung.reflection.Bird"); שדה [] שדות = birdClass.getDeclaredFields (); assertEquals (1, fields.length); assertEquals ("הליכות", שדות [0] .getName ()); }

אנו יכולים גם להשתמש בגרסה האחרת שלו למקרה שנדע את שם השדה:

@Test הציבור בטל givenClass_whenGetsFieldsByName_thenCorrect () {Class birdClass = Class.forName ("com.baeldung.reflection.Bird"); שדה שדה = birdClass.getDeclaredField ("הולך"); assertEquals ("הליכות", field.getName ()); }

אם נקבל שם של השדה שגוי או נקליד שדה קיים, נקבל NoSuchFieldException.

אנו מקבלים את סוג השדה באופן הבא:

@Test ציבורי בטל givenClassField_whenGetsType_thenCorrect () {שדה שדה = Class.forName ("com.baeldung.reflection.Bird") .getDeclaredField ("הולך"); Class fieldClass = field.getType (); assertEquals ("בוליאני", fieldClass.getSimpleName ()); }

לאחר מכן, נבחן כיצד לגשת לערכי שדה ולשנות אותם. כדי שנוכל לקבל את הערך של שדה, שלא לדבר על הגדרתו, עלינו להגדיר תחילה שהוא נגיש באמצעות שיחה setAccessible שיטה על שדה להתנגד ולהעביר בוליאני נָכוֹן לזה:

@ מבחן הריק פומבי givenClassField_whenSetsAndGetsValue_thenCorrect () {Class birdClass = Class.forName ("com.baeldung.reflection.Bird"); ציפור ציפורים = (Bird) birdClass.getConstructor (). NewInstance (); שדה שדה = birdClass.getDeclaredField ("הולך"); field.setAccessible (נכון); assertFalse (field.getBoolean (ציפור)); assertFalse (bird.walks ()); field.set (ציפור, נכון); assertTrue (field.getBoolean (ציפור)); assertTrue (bird.walks ()); }

במבחן הנ"ל אנו מבררים כי אכן ערך ה - הולך שדה הוא שקר לפני שמגדירים אותו נכון.

שימו לב כיצד אנו משתמשים ב- שדה התנגד להגדיר ולקבל ערכים על ידי העברת זה למופע המחלקה שאנו עוסקים בה ואולי לערך החדש שאנו רוצים שהשדה יהיה באותו אובייקט.

דבר אחד חשוב לציין עליו שדה אובייקטים זה שכאשר הוא מוכרז כ- סטטי ציבורי, אז אנחנו לא צריכים מופע של הכיתה שמכילה אותם, אנחנו יכולים פשוט לעבור ריק במקומו ועדיין להשיג את ערך ברירת המחדל של השדה, כך:

@Test הציבור בטל givenClassField_whenGetsAndSetsWithNull_thenCorrect () {Class birdClass = Class.forName ("com.baeldung.reflection.Bird"); שדה שדה = birdClass.getField ("CATEGORY"); field.setAccessible (נכון); assertEquals ("מקומי", field.get (null)); }

8. שיטות בדיקה

בדוגמה קודמת השתמשנו בבבואה רק כדי לבדוק שמות שיטות. עם זאת, השתקפות Java חזקה יותר מכך.

עם השתקפות Java, אנחנו יכולים להפעיל שיטות ב זמן ריצה ולהעביר להם את הפרמטרים הנדרשים שלהם, בדיוק כמו שעשינו עבור בונים. באופן דומה, אנו יכולים גם להפעיל שיטות עמוסות על ידי ציון סוגי פרמטרים של כל אחת מהן.

בדיוק כמו שדות, ישנן שתי שיטות עיקריות בהן אנו משתמשים לאחזור שיטות כיתה. ה getMethods שיטה מחזירה מערך של כל השיטות הציבוריות של הכיתה ושל מחלקות העל.

המשמעות היא שעם שיטה זו נוכל להשיג שיטות ציבוריות של java.lang. אובייקט כיתה כמו toString, hashCode, ו להודיע ​​הכל:

@Test הציבור בטל givenClass_whenGetsAllPublicMethods_thenCorrect () {Class birdClass = Class.forName ("com.baeldung.reflection.Bird"); שיטה [] שיטות = birdClass.getMethods (); רשימת methodNames = getMethodNames (שיטות); assertTrue (methodNames.containsAll (Arrays .asList ("שווה", "notifyAll", "hashCode", "הולך", "אוכל", "toString")); }

כדי להשיג רק שיטות ציבוריות של הכיתה בה אנו מעוניינים, עלינו להשתמש getDeclaredMethods שיטה:

@Test הציבור בטל givenClass_whenGetsOnlyDeclaredMethods_thenCorrect () {Class birdClass = Class.forName ("com.baeldung.reflection.Bird"); רשימת actualMethodNames = getMethodNames (birdClass.getDeclaredMethods ()); רשימה expectMethodNames = מערכים .asList ("setWalks", "הליכות", "getSound", "אוכל"); assertEquals (expectMethodNames.size (), actualMethodNames.size ()); assertTrue (expectMethodNames.containsAll (actualMethodNames)); assertTrue (actualMethodNames.containsAll (expectedMethodNames)); }

לכל אחת משיטות אלה יש את הווריאציה היחידה המחזירה יחיד שיטה חפץ שאת שמו אנו מכירים:

@Test הציבור בטל givenMethodName_whenGetsMethod_thenCorrect () זורק חריג {ציפור ציפור = ציפור חדשה (); שיטה walkMethod = bird.getClass (). GetDeclaredMethod ("הולך"); שיטה setWalksMethod = bird.getClass (). GetDeclaredMethod ("setWalks", בוליאני.קלאס); assertTrue (walkMethod.canAccess (ציפור)); assertTrue (setWalksMethod.canAccess (ציפור)); }

שימו לב כיצד אנו מאחזרים שיטות בודדות ומציינים אילו סוגי פרמטרים הם לוקחים. אלה שאינם לוקחים סוגי פרמטרים נשלפים עם ארגומנט משתנה ריק, ומשאיר לנו רק ארגומנט יחיד, שם השיטה.

לאחר מכן, נראה כיצד להפעיל שיטה בזמן הריצה. אנו יודעים כברירת מחדל כי ה- הולך תכונה של ציפור הכיתה היא שֶׁקֶר, אנחנו רוצים לקרוא לזה setWalks שיטה והגדר אותה ל נָכוֹן:

@Test הציבור בטל givenMethod_whenInvokes_thenCorrect () {Class birdClass = Class.forName ("com.baeldung.reflection.Bird"); ציפור ציפורים = (Bird) birdClass.getConstructor (). NewInstance (); שיטה setWalksMethod = birdClass.getDeclaredMethod ("setWalks", בוליאני.קלאס); שיטה walkMethod = birdClass.getDeclaredMethod ("הליכות"); הליכות בוליאניות = (בוליאניות) הליכות Method.invoke (ציפור); assertFalse (הליכות); assertFalse (bird.walks ()); setWalksMethod.invoke (ציפור, נכון); הליכות בוליאניות 2 = (בוליאניות) הליכות Method.invoke (ציפור); assertTrue (הליכות 2); assertTrue (bird.walks ()); }

שימו לב כיצד אנו קוראים לראשונה את הולך שיטה והשליך את סוג ההחזרה לסוג הנתונים המתאים ואז בדוק את ערכו. אחר כך אנו קוראים את ה- setWalks שיטה לשנות ערך זה ולבדוק שוב.

9. מסקנה

במדריך זה סקרנו את ה- API של השתקפות Java ובדקנו כיצד להשתמש בו לבדיקת שיעורים, ממשקים, שדות ושיטות בזמן הריצה ללא ידיעה מוקדמת על הפנימיות שלהם לפי זמן הידור.

קוד המקור המלא ודוגמאות למדריך זה ניתן למצוא באתר GitHub.