Java 101: השפה החיונית של Java כוללת סיור, חלק 5

הקודם 1 2 עמוד 2 עמוד 2 מתוך 2

הקלד קונסטרוקציות מסקנות וגנריות לשיעורים גנריים ולא גנריים

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

 public class Box { public  Box(T t) { // ... } } 

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

 new Box("Aggies") 

ביטוי זה יוצר מופע של Box, עובר Marbleאל E. כמו כן, מסיק המהדר Stringכמו Tטיעון מהסוג בפועל של" כי הטענה של הבנאי הוא Stringאובייקט.

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

 Box box = new Box("Aggies"); 

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

מטבע פרויקט שינוי קטן מס '8: הפעלת שיטת varargs פשוטה

לפני Java 7, כל ניסיון לעורר varargs (ארגומנטים של משתנים, הידוע גם בשם arity משתנה ) שיטה עם-reifiable הלא varargs סוג גרם מהדר פלט אזהרה "מבצע לא בטוח". כדי לבטל את הפוטנציאל להרבה הודעות אזהרה דומות (אחת לכל שיחה), Java 7 העביר את האזהרה מאתר השיחות להצהרת השיטה.

סוגים ניתנים לשיקום ולא ניתן לשלם

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

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

רישום 13 מדגים זיהום ערימה בהקשר שאינו Varargs.

רישום 13. הדגמת זיהום ערימה בהקשר שאינו Varargs

 import java.util.Iterator; import java.util.Set; import java.util.TreeSet; public class HeapPollutionDemo { public static void main(String[] args) { Set s = new TreeSet(); Set ss = s; // unchecked warning s.add(new Integer(42)); // another unchecked warning Iterator iter = ss.iterator(); while (iter.hasNext()) { String str = iter.next(); // ClassCastException thrown System.out.println(str); } } } 

למשתנה ssיש סוג של פרמטרים Set. כאשר java.util.Setזה הפניה sמוקצה ss, המהדר מייצר אזהרה מסומנת. הוא עושה זאת מכיוון שהמהדר לא יכול לקבוע sשמתייחס Setלסוג (הוא לא). התוצאה היא זיהום ערימה. (המהדר מאפשר למשימה זו לשמור על תאימות לאחור עם גרסאות ג'אווה מדור קודם שאינן תומכות בגנריות. יתר על כן, מחיקת סוג הופכת Setל Set, מה שמביא להקצאת אחת Setלאחרת Set.)

המהדר מייצר אזהרה שנייה לא מסומנת בשורה שמפעילה Setאת add()השיטה. הוא עושה זאת מכיוון שאינו יכול לקבוע אם משתנה sמתייחס לסוג Setאו Setלסוג. זהו מצב זיהום ערימה נוסף. (המהדר מאפשר קריאה לשיטה זו מכיוון שהמחיקה הופכת Setאת boolean add(E e)שיטת ה boolean add(Object o), אשר יכולה להוסיף כל סוג של אובייקט לסט, כולל java.lang.Integerתת - הסוג של java.lang.Object.)

זיהום ערימה יכול להתרחש בקלות בהקשר של varargs. לדוגמה, שקול רישום 14.

רישום 14. הדגמת זיהום ערימה בהקשר של וארגס

 import java.util.Arrays; import java.util.List; public class UnsafeVarargsDemo { public static void main(String[] args) { unsafe(Arrays.asList("A", "B", "C"), Arrays.asList("D", "E", "F")); } static void unsafe(List... l) { Object[] oArray = l; oArray[0] = Arrays.asList(new Double(3.5)); String s = l[0].get(0); } } 

Object[] oArray = l;המשימה מציגה את האפשרות של זיהום ערימה. lניתן להקצות למשתנה ערך שאינו תואם את סוג הפרמטרים של פרמטר varargs oArray. עם זאת, המהדר אינו מייצר אזהרה לא מסומנת מכיוון שכבר עשה זאת בעת תרגום List... lל- List[] l. מטלה זו תקפה מכיוון שלמשתנה lיש את הסוג List[], איזה תת-סוגים Object[].

כמו כן, המהדר אינו מעביר אזהרה או שגיאה בעת הקצאת Listאובייקט מכל סוג שהוא oArrayלמרכיבי המערך; למשל oArray[0] = Arrays.asList(new Double(3.5));,. הקצאה זו מקצה לרכיב הראשון במערך של אובייקט המכיל יחיד אובייקט.oArrayListjava.lang.Double

String s = l[0].get(0);המשימה היא בעייתית. האובייקט המאוחסן ברכיב המערך הראשון של המשתנה lמכיל את הסוג List, אך בהקצאה זו מצפה אובייקט מסוג List. כתוצאה מכך ה- JVM זורק java.lang.ClassCastException.

הידור קוד המקור הזה ( javac -Xlint:unchecked UnsafeVarargsDemo.java). עליך להתבונן בפלט הבא (מעוצב מחדש מעט לקריאות) בעת הידורו תחת עדכון 6 של Java SE 7:

 UnsafeVarargsDemo.java:8: warning: [unchecked] unchecked generic array creation for varargs parameter of type List[] unsafe(Arrays.asList("A", "B", "C"), ^ UnsafeVarargsDemo.java:12: warning: [unchecked] Possible heap pollution from parameterized vararg type List static void unsafe(List... l) ^ 2 warnings 

במבוא שלי ל- Java 101 לגנריות אמרתי כי אינך יכול להשתמש בפרמטרי סוג בביטויים ליצירת מערך. לדוגמא, אינך יכול לציין elements = new E[size];. המהדר מדווח על הודעת "שגיאת יצירת מערך כללי" כשאתה מנסה לעשות זאת. עם זאת, עדיין ניתן ליצור מערך כללי, אך רק בהקשר של varargs, ועל כך מדווחת הודעת האזהרה הראשונה. מאחורי הקלעים, המהדר הופך List... lל List[] lואז List[] l.

שימו לב כי אזהרת זיהום הערימה מופקת unsafe()באתר ההצהרה של השיטה. הודעה זו אינה נוצרת באתר השיחות של שיטה זו, וזה המקרה עם מהדרים Java 5 ו- 6.

לא כל שיטות ה- varargs יתרמו לזיהום ערימה. עם זאת, הודעת אזהרה עדיין תונפק באתר ההצהרה של השיטה. אם אתה יודע שהשיטה שלך לא תורמת לזיהום ערימה, אתה יכול לדכא את האזהרה הזו על ידי הכרזתה עם @SafeVarargsההערה - Java 7 הציגה את java.lang.SafeVarargsסוג ההערה. לדוגמה, מכיוון שאין שום דרך לשיטת Arraysהכיתה asList()לתרום לזיהום ערימה, ההצהרה על שיטה זו הוסרה @SafeVarargsכדלקמן:

 @SafeVarargs public static  List asList(T... a) 

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

לסיכום

Java 7 שיפרה את פרודוקטיביות המפתחים על ידי הנהגת ניהול משאבים אוטומטי באמצעות הצהרת ניסיון-עם-משאבים יחד עם AutoCloseableממשק חדש, הפעלת מחרוזת, רב-תפיסה, סידור חוזר אחרון, ליטרלים בינאריים, קו תחתון בספרות ספרותיות, שינויים בסוג המהדר אלגוריתם ההסקות שהציג את מה שמכונה מפעיל היהלומים, והפנה להפעלת שיטת varargs. הבא ב- Java 101: סדרת הדור הבא היא מבט על מאפייני ה- lambda של Java 8 וממשק פונקציונלי.

סיפור זה, "Java 101: השפה החיונית של Java כולל סיור, חלק 5" פורסם במקור על ידי JavaWorld.