המרה אובדת בג'אווה
1. סקירה כללית
במדריך מהיר זה נדון במושג המרה אובדן ב- Java ובסיבה העומדת מאחוריו.
במקביל, נחקור כמה טכניקות המרה שימושיות כדי למנוע שגיאה זו.
2. המרה מאובדת
המרה אובדן היא פשוט אובדן מידע בזמן הטיפול בנתונים. בג'אווה זה תואם את האפשרות של אובדן הערך או הדיוק של המשתנה בזמן ההמרה סוג אחד למשנהו. כאשר אנו מנסים להקצות משתנה של סוג בגודל גדול לסוג בגודל קטן יותר, ג'אווה תיצור שגיאה, סוגים שאינם תואמים: המרה אובדנית אפשרית, תוך כדי קומפילציה של הקוד. לדוגמה, בואו ננסה להקצות a ארוך ל int: ג'אווה תנפיק שגיאה בעת הידור קוד זה: כאן, ג'אווה תמצא ארוך ו int לא תואם וגורם לשגיאת המרה אבודה. כי יכול להיות ארוך ערכים מחוץ ל int טווח -2,147,483,648 עד 2,147,483,647. באופן דומה, בואו ננסה להקצות a לָצוּף אל א ארוך: כפי ש לָצוּף יכולות להיות ערכים עשרוניים שאין להם התאמה ארוך ערך. לכן, נקבל את אותה שגיאה. באופן דומה, הקצאת א לְהַכפִּיל מספר ל- int יגרום לאותה שגיאה: ה לְהַכפִּיל ערכים יכולים להיות גדולים מדי או קטנים מדי עבור int וערכים עשרוניים ילכו לאיבוד בהמרה. לפיכך, מדובר בהמרה אבדתית. כמו כן, אנו יכולים להיתקל בשגיאה זו בעת ביצוע חישוב פשוט: כש לְהַכפִּיל להכפיל עם int, אנו מקבלים את התוצאה ב- לְהַכפִּיל. כתוצאה מכך, מדובר גם בהמרה אבדתית. לכן, הסוגים שאינם תואמים ב- המרה אובדנית יכולה להיות בגדלים או סוגים שונים (מספרים שלמים או עשרוניים). בג'אווה קיימים סוגי נתונים פרימיטיביים רבים עם שיעורי העטיפה המתאימים להם. לאחר מכן, בואו נערך רשימה שימושית של כל ההמרות האבדות האפשריות ב- Java: שים לב שלמרות זאת קצר ו לְהַשְׁחִיר יש את אותו הגודל. עוֹד, ההמרה מ קצר ל לְהַשְׁחִיר הוא אובדן כי לְהַשְׁחִיר הוא סוג נתונים לא חתום. הדרך הקלה להמיר פרימיטיביים כדי למנוע גיור אובדן היא באמצעות השלכת נפילות; במילים אחרות, יציקת הסוג בגודל גדול יותר לסוג בגודל קטן יותר. לפיכך, זה נקרא גם צמצום המרה פרימיטיבית. למשל, בואו להמיר ארוך מספר ל- a קצר באמצעות downcasting: באופן דומה, בואו להמיר א לְהַכפִּיל ל int: עם זאת, נציין כי המרת סוג בגודל גדול עם ערכים גדולים מדי או קטנים מדי לסוג בגודל קטן יותר באמצעות downcasting יכולה לגרום לערכים בלתי צפויים. בואו נתגייר ארוך ערכים מחוץ לטווח קצר: אם ננתח בקפידה את ההמרה, נראה שלא מדובר בערכים הצפויים. במילים אחרות, כאשר ג'אווה פוגעת בערך הגבוה ביותר של סוג בגודל קטן בזמן ההמרה מסוג בגודל גדול, המספר הבא הוא הערך הנמוך ביותר מהסוג בגודל קטן ולהיפך. בואו נבין זאת באמצעות דוגמאות. מתי largeLongNum עם הערך 32768 מומר ל קצר, הערך של shortNum1 הוא -32768. מכיוון שהערך המקסימלי של קצר הוא 32767, לכן Java הולכת לערך הדקות הבא של ה- קצר. באופן דומה, מתי smallLongNum מומר ל קצר. הערך של shortNum2 הוא 32767 כאשר Java הולכת לערך המקסימלי הבא של קצר. כמו כן, בואו נראה מה קורה כאשר אנו ממירים את ערכי המקסימום והמינימום של a ארוך ל int: כדי להמיר ישירות אובייקט עטיפה לפרימיטיבי, אנו יכולים להשתמש בשיטות שונות בכיתות עטיפה כגון intValue (), shortValue () ו longValue (). זה נקרא ביטול איגרוף. למשל, בואו להמיר א לָצוּף התנגדות ל ארוך: כמו כן, אם נסתכל על היישום של longValue או בשיטות דומות, נמצא את השימוש בהמרה פרימיטיבית מצמצמת: עם זאת, לעיתים יש להימנע מהמרה פרימיטיבית מצמצמת כדי לשמור מידע רב ערך: לאחר ההמרה, הערך של longNum יהיה בן 15. עם זאת, ה doubleNum הוא 15.9999, שזה קרוב מאוד ל -16. במקום זאת, אנו יכולים להשתמש Math.round () להמרה למספר השלם הקרוב ביותר: לשם כך, בואו נשתמש בטכניקות ההמרה שנדונו כבר. ראשית, נתגייר עצם עטיפה לערך פרימיטיבי, הורידו אותו והמירו אותו לאובייקט עטיפה אחר. במילים אחרות, אנו נבצע טכניקות של Unboxing, Downcasting ו- Boxing. לדוגמא, בואו להמיר א לְהַכפִּיל להתנגד ל- מספר שלם לְהִתְנַגֵד: לבסוף, אנו משתמשים מספר שלם.ערך של() להמיר את הסוג הפרימיטיבי int ל מספר שלם לְהִתְנַגֵד. סוג זה של המרה נקרא אִגרוּף. במאמר זה בחנו את הרעיון של המרה אובדתית בג'אווה בעזרת מספר דוגמאות. בנוסף, ריכזנו רשימה שימושית של כל ההמרות האבדות האפשריות גם כן. בדרך, זיהינו צמצום של המרה פרימיטיבית כטכניקה קלה להמרת מספרים פרימיטיביים ולהימנע משגיאת ההמרה האבודה. במקביל בחנו גם טכניקות שימושיות נוספות להמרות מספריות בג'אווה. יישומי הקוד עבור מאמר זה ניתן למצוא באתר GitHub.longNum ארוך = 10; int intNum = longNum;
סוגים שאינם תואמים: המרה אובדנית אפשרית מ- long ל- int
float floatNum = 10.12f; longNum ארוך = floatNum;
סוגים שאינם תואמים: המרה אובדנית אפשרית מ- float ל- long
כפול כפול = 1.2; int intNum = doubleNum;
סוגים שאינם תואמים: המרה אובדנית אפשרית מכפול ל- int
פרנהייט = 100; int celcius = (פרנהייט - 32) * 5.0 / 9.0;
3. סוגי נתונים פרימיטיביים
4. טכניקות המרה
4.1. המרה בין סוגים פרימיטיביים
longNum ארוך = 24; קצר shortNum = (קצר) longNum; assertEquals (24, shortNum);
כפול כפול = 15.6; int integerNum = (int) doubleNum; assertEquals (15, integerNum);
ארוך גדולLongNum = 32768; shortShortNum קצר = (short) largeLongNum; assertEquals (-32768, minShortNum); ארוך smallLongNum = -32769; קצר maxShortNum = (קצר) smallLongNum; assertEquals (32767, maxShortNum);
ארוך maxLong = Long.MAX_VALUE; int minInt = (int) maxLong; assertEquals (-1, minInt); ארוך minLong = ארוך.MIN_VALUE; int maxInt = (int) minLong; assertEquals (0, maxInt);
4.2. המרה בין חפצי עטיפה לסוגים פרימיטיביים
Float floatNum = 17.564f; longNum ארוך = floatNum.longValue (); assertEquals (17, longNum);
ציבורי long longValue () {return (long) value; }
כפול כפול = 15.9999; longNum ארוך = doubleNum.longValue (); assertEquals (15, longNum);
כפול כפול = 15.9999; longNum ארוך = Math.round (doubleNum); assertEquals (16, longNum);
4.3. המרה בין אובייקטים של עטיפה
כפול כפול = 10.3; כפול dbl = doubleNum.doubleValue (); // unboxing int intgr = (int) dbl; // downcasting Integer intNum = Integer.valueOf (intgr); assertEquals (Integer.valueOf (10), intNum);
5. מסקנה