מבנים סינתטיים בג'אווה

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

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

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

2. סינטטי בג'אווה

ההגדרה הטובה ביותר של מְלָאכוּתִי אנו יכולים למצוא שמגיע ישירות ממפרט שפת Java (JLS 13.1.7):

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

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

ללא התייחסות נוספת, בואו להעמיק בכל אחד מאלה.

3. שדות סינתטיים

נתחיל בשיעור מקונן פשוט:

מחלקה ציבורית SyntheticFieldDemo {class NestedClass {}}

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

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

חלל ציבורי givenSyntheticField_whenIsSynthetic_thenTrue () {שדה [] שדות = SyntheticFieldDemo.NestedClass.class .getDeclaredFields (); assertEquals ("מחלקה זו צריכה להכיל שדה אחד בלבד", 1, שדות. אורך); עבור (שדה f: שדות) {System.out.println ("שדה:" + f.getName () + ", isSynthetic:" + f.isSynthetic ()); assertTrue ("כל השדות של מחלקה זו צריכים להיות סינתטיים", f.isSynthetic ()); }}

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

4. שיטות סינתטיות

בהמשך, נוסיף שדה פרטי למחלקה המקוננת שלנו:

מחלקה ציבורית SyntheticMethodDemo {class NestedClass {private String nestedField; } מחרוזת ציבורית getNestedField () {להחזיר NestedClass חדש (). nestedField; } public void setNestedField (String nestedField) {new NestedClass (). nestedField = nestedField; }}

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

שוב נוכל לבדוק זאת באותה טכניקה המציגה שתי שיטות סינתטיות הנקראות גישה 0 $ ו גישה $ 1:

חלל ציבורי givenSyntheticMethod_whenIsSynthetic_thenTrue () {Method [] שיטות = SyntheticMethodDemo.NestedClass.class .getDeclaredMethods (); assertEquals ("מחלקה זו צריכה להכיל שתי שיטות בלבד", 2, methods.length); עבור (שיטה m: שיטות) {System.out.println ("שיטה:" + m.getName () + ", isSynthetic:" + m.isSynthetic ()); assertTrue ("כל השיטות של מחלקה זו צריכות להיות סינתטיות", m.isSynthetic ()); }}

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

כאמור לעיל, שיטות סינתטיות אלה כבר לא נוצרות החל מ- JDK 11.

4.1. שיטות גשר

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

לדוגמה, בואו ניקח בחשבון פשוט משווה:

מחלקה ציבורית BridgeMethodDemo מיישמת את המשווה {@Override public int השווה (מספר שלם o1, מספר שלם o2) {החזר 0; }}

למרות ש לְהַשְׁווֹת() לוקח שניים מספר שלם טיעונים במקור, לאחר הידור זה ייקח שניים לְהִתְנַגֵד במקום זאת, בגלל מחיקת סוגים.

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

public int השווה (אובייקט o1, אובייקט o2) {השווה השוואה ((שלם) o1, (שלם) o2); }

בנוסף למבחנים הקודמים שלנו, הפעם גם נתקשר isBridge () מ ה שיטה מעמד:

חלל ציבורי givenBridgeMethod_whenIsBridge_thenTrue () {int syntheticMethods = 0; שיטה [] שיטות = BridgeMethodDemo.class.getDeclaredMethods (); עבור (שיטה m: שיטות) {System.out.println ("שיטה:" + m.getName () + ", isSynthetic:" + m.isSynthetic () + ", isBridge:" + m.isBridge ()); אם (m.isSynthetic ()) {סינתטי מתודות ++; assertTrue ("השיטה הסינתטית בכיתה זו צריכה להיות גם שיטת גשר", m.isBridge ()); }} assertEquals ("צריכה להיות בדיוק שיטת גשר סינטטי אחת בכיתה זו", 1, synthethodes); }

5. קונסטרוקטורים סינתטיים

לבסוף, נוסיף קונסטרוקטור פרטי:

מחלקה ציבורית SyntheticConstructorDemo {פרטי NestedClass nestedClass = NestedClass חדש (); class NestedClass {private NestedClass () {}}}

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

חלל ציבורי givenSyntheticConstructor_whenIsSynthetic_thenTrue () {int syntheticConstructors = 0; קונסטרוקטור [] קונסטרוקטורים = SyntheticConstructorDemo.NestedClass .class.getDeclaredConstructors (); assertEquals ("מחלקה זו צריכה להכיל רק שני קונסטרוקטורים", 2, constructors.length); עבור (קונסטרוקטור c: קונסטרוקטורים) {System.out.println ("קונסטרוקטור:" + c.getName () + ", isSynthetic:" + c.isSynthetic ()); אם (c.isSynthetic ()) {סינתטי קונסטרוקטורים ++; }} assertEquals (1, Constructors סינתטיים); }

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

כאמור לעיל, הבנאי הסינתטי כבר לא נוצר החל מ- JDK 11.

6. מסקנה

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

כמו תמיד, כל הקוד זמין ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found