JavaRush /בלוג Java /Random-HE /אוטו-בוקסינג ו-unboxing ב-Java
Viacheslav
רָמָה

אוטו-בוקסינג ו-unboxing ב-Java

פורסם בקבוצה
<h2>מבוא</h2>שפת תכנות, כמו השפה שאנשים מדברים, חיה ומשתנה, מופיעות בה תופעות חדשות כדי להפוך את השפה לנוחה יותר לשימוש. וכידוע, השפה צריכה לבטא את מחשבותינו בצורה נוחה.
אוטו-בוקסינג ו-unboxing ב-Java - 1
אז, ב-Java SE 5, מנגנון האגרוף/ unboxing הוצג. ומדריך נפרד מ-Oracle מוקדש לתכונות של אמצעי זה לביטוי מחשבות: Autoboxing ו- Unboxing . <h2>אגרוף אריזה אוטומטית</h2>בואו נסתכל על דוגמה של אגרוף אריזה אוטומטית. ראשית, בואו נראה איך זה עובד. בואו נשתמש באתר compilejava.net וניצור מחלקה:
public class App {
    public static void main(String[] args) {
        Integer portNumber = 8080;
        if (args.length != 0) {
            portNumber = Integer.valueOf(args[0]);
        }
        System.out.println("Port number is: " + portNumber);
    }
}
קוד פשוט. אנו יכולים לציין את פרמטר הקלט ולשנות את ערך היציאה. כפי שאנו רואים, כי אנו קוראים את ערך היציאה מהפרמטרים String, אנו מקבלים Integerאותו על ידי העברתו דרך Integer.valueOf. לכן, אנו נאלצים לציין אותו לא כסוג פרימיטיבי, אלא כסוג אובייקט Integer. והנה אנחנו מקבלים, מצד אחד, יש לנו משתנה אובייקט, וערך ברירת המחדל הוא פרימיטיבי. וזה עובד. אבל אנחנו לא מאמינים בקסם, נכון? בואו נסתכל "מתחת למכסה המנוע", כמו שאומרים. הורד את קוד המקור מ compilejava.net על ידי לחיצה על "הורד ZIP". לאחר מכן, חלץ את הארכיון שהורדת לתוך ספרייה ועבור אליו. עכשיו בוא נעשה: javap -c -p App.classכאשר App.class הוא קובץ המחלקה המהודר עבור הכיתה שלך. נראה תוכן כזה:
אוטו-בוקסינג ו-unboxing ב-Java - 2
זהו אותו "קוד בייט" הידוע לשמצה. אבל מה שחשוב לנו עכשיו זה מה שאנחנו רואים. ראשית, הפרימיטיבי 8080 ממוקם על מחסנית ביצוע השיטה, ולאחר מכן מבוצע Integer.valueOf . זה ה"קסם" של האגרוף. ובפנים הקסם נראה כך:
אוטו-בוקסינג ו-unboxing ב-Java - 3
כלומר, בעצם, אחד חדש יילקח Integerאו יתקבל Integerמהמטמון (המטמון הוא לא יותר מסתם מערך של מספרים שלמים) בהתאם לערך המספר. כמובן, Integerלא רק אחד היה כל כך בר מזל. יש רשימה שלמה של טיפוסים פרימיטיביים קשורים והעטיפות שלהם (מעמדות המייצגים פרימיטיביים בעולם OOP). רשימה זו ניתנת בחלק התחתון של המדריך מבית אורקל: " איגרס אוטומטי וביטול ארגז ". ראוי לציין מיד שלמערכים העשויים מפרימיטיבים אין "עטיפה" מבלי לחבר ספריות של צד שלישי כלשהן. הָהֵן. Arrays.asListלא יעשה מ int[]עבורנו Listמ Integer'. <h2>Unboxing</h2>התהליך ההפוך לאיגרוף נקרא unboxing unboxing. בואו נסתכל על דוגמה של פריקת אריזה:
public class App {

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Please, enter params");
            return;
        }
      	int value = Math.abs(Integer.valueOf(args[0]));
        System.out.println("Absolute value is: " + value);
    }

}
Math.absמקבל רק פרימיטיבים. מה לעשות? למחלקת העטיפה יש שיטה מיוחדת למקרה הזה שמחזירה פרימיטיבי. לדוגמה, זוהי Integerשיטת intValue . אם נסתכל על ה-bytecode, הוא נראה כך:
אוטו-בוקסינג ו-unboxing ב-Java - 4
לכאורה, אין קסם. הכל בתוך ג'אווה. זה פשוט עובד "מעצמו". לנוחיותנו. <h2>גרף</h2>
אוטו-בוקסינג ו-unboxing ב-Java - 5
כל כלי, אם נעשה בו שימוש לא נכון, הופך לנשק אדיר נגד עצמו. ומנגנון האגרוף/ unboxing האוטומטי בג'אווה אינו יוצא מן הכלל. ההשוואה הראשונה והברורה היא דרך ==. אני חושב שזה ברור, אבל בואו נסתכל על זה שוב:
public static void main(String[] args) {
    Integer inCacheValue = 127;
    Integer inCacheValue2 = 127;
    Integer notInCache = 128; // new Integer(129)
    Integer notInCache2 = 128; // new Integer(129)
    System.out.println(inCacheValue == inCacheValue2); //true
    System.out.println(notInCache == notInCache2); //false
}
במקרה הראשון, הערך נלקח ממטמון Integerהערכים (ראה הסבר על Boxing למעלה), ובמקרה השני יווצר אובייקט חדש בכל פעם. אבל כאן כדאי להזמין מקום. התנהגות זו תלויה בגבול המטמון הגבוה ( java.lang.Integer.IntegerCache.high ). בנוסף, מגבלה זו עשויה להשתנות עקב הגדרות אחרות. אתה יכול לקרוא את הדיון בנושא זה על stackoverflow: כמה גדול מטמון ה-Integer? באופן טבעי, יש להשוות בין אובייקטים באמצעות שווים: System.out.println(notInCache.equals(notInCache2)); הבעיה השנייה הקשורה לאותו מנגנון היא ביצועים. כל איגרוף בג'אווה שווה ערך ליצירת אובייקט חדש. אם המספר אינו כלול בערכי המטמון (כלומר -128 עד 127), אזי ייווצר אובייקט חדש בכל פעם. אם לפתע מבצעים אריזה (כלומר אגרוף) בלולאה, הדבר יגרום לגידול עצום בחפצים מיותרים וצריכת משאבים לעבודת אוסף האשפה. לכן, אל תהיה פזיז מדי לגבי זה. גריפה שלישית, לא פחות כואבת, נובעת מאותו מנגנון:
public static void check(Integer value) {
    if (value <= 0) {
        throw new IllegalStateException("Value is too small");
    }
}
בקוד זה, ברור שהאדם ניסה לא לעבור את השגיאה. אבל אין בדיקה עבור null. אם זה מגיע לקלט null, אז במקום שגיאה מובנת נקבל שגיאה לא מובנת NullPointerException. כי לשם השוואה, ג'אווה תנסה להפעיל value.intValueולקרוס, כי... valueיהיה null. <h2>מסקנה</h2>מנגנון ה-boxing/unboxing מאפשר למתכנת לכתוב פחות קוד ולפעמים אפילו לא לחשוב על המרה מפרימיטיבים לאובייקטים ובחזרה. אבל זה לא אומר שאתה צריך לשכוח איך זה עובד. אחרת, אתה עלול לעשות טעות שאולי לא תופיע מיד. אל לנו להסתמך על חלקים במערכת שאינם בשליטתנו לחלוטין (כגון גבול המספרים השלמים). אבל אל תשכח את כל היתרונות של שיעורי עטיפה (כמו Integer). לעתים קרובות לשיעורי העטיפה הללו יש קבוצה של שיטות סטטיות נוספות שיהפכו את החיים שלך לטובים יותר ואת הקוד שלך יותר אקספרסיבי. הנה דוגמה לתפיסה:
public static void main(String[] args) {
    int first = 1;
    int second = 5;
    System.out.println(Integer.max(first, second));
    System.out.println(Character.toLowerCase('S'));
}
המסקנה הנכונה מכל דבר היא שאין קסם, יש איזושהי מימוש. ולא תמיד הכל יהיה מה שאנחנו מצפים. לדוגמה, אין אריזה: System.out.println("The number is " + 8); הדוגמה שלמעלה תעבור אופטימיזציה על ידי המהדר לשורה אחת. כלומר, זה כאילו כתבת "המספר הוא 8". וגם בדוגמה למטה לא תהיה אריזה:
public static void main(String[] args) {
    System.out.println("The number is " + Math.abs(-2));
}
איך זה יכול להיות כשאנחנו printlnלוקחים אובייקט כקלט וצריכים איכשהו לחבר את הקווים. קווים... כן, בגלל זה אין אריזה ככזו. ישנן Integerשיטות סטטיות, אבל חלקן הן package. כלומר, אנחנו לא יכולים להשתמש בהם, אבל בג'אווה עצמה ניתן להשתמש בהם באופן פעיל. זה בדיוק המקרה כאן. תיקרא שיטת getChars, שעושה מערך של תווים מהמספר. שוב, אין קסם, רק ג'אווה). אז בכל מצב לא ברור, אתה רק צריך להסתכל על היישום ולפחות משהו יגיע למקום. #ויאצ'סלב
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION