JavaRush /בלוג Java /Random-HE /יציקה (המרה) של טיפוסים פרימיטיביים בג'אווה

יציקה (המרה) של טיפוסים פרימיטיביים בג'אווה

פורסם בקבוצה
שלום! בזמן שעברת על JavaRush, נתקלת בטיפוסים פרימיטיביים יותר מפעם אחת. הנה רשימה קצרה של מה שאנחנו יודעים עליהם:
  1. הם אינם אובייקטים ומייצגים ערך המאוחסן בזיכרון
  2. ישנם מספר סוגים של טיפוסים פרימיטיביים:
    • מספרים שלמים - byte, short, int,long
    • מספרי נקודה צפה (שברית) - floatוdouble
    • בוליאנית -boolean
    • סמלי (כדי לציין אותיות ומספרים) -char
  3. לכל אחד מהם טווח ערכים משלו:
סוג פרימיטיבי גודל בזיכרון טווח ערכים
בייט 8 ביט -128 עד 127
קצר 16 ביט ל-32768 עד 32767
לְהַשְׁחִיר 16 ביט מ-0 ל-65536
int 32 ביטים מ-2147483648 ל-2147483647
ארוך 64 ביטים מ-9223372036854775808 ל-9223372036854775807
לָצוּף 32 ביטים מ-(2 בחזקת -149) ל-((2-2 בחזקת -23)*2 בחזקת 127)
לְהַכפִּיל 64 ביטים מ-(-2 בחזקת 63) ל-((2 בחזקת 63) - 1)
בוליאני 8 (בשימוש במערכים), 32 (בשימוש בלא-מערכים) אמת או שקר
אבל, בנוסף לערכים, סוגים שונים גם בגודל הזיכרון. intלוקח יותר מ byte. א long- יותר מ short. ניתן להשוות את כמות הזיכרון שתופסת הפרימיטיבים לבובות קינון: הרחבה והתכווצות של טיפוסים פרימיטיביים - 2 יש מקום פנוי בתוך בובת הקינון. ככל שבובת הקינון גדולה יותר, כך יותר מקום. longאנחנו יכולים בקלות לשים אחד קטן יותר בתוך בובת קינון גדולה int. זה מתאים בקלות ואתה לא צריך לעשות שום דבר נוסף. ב-Java, כאשר עובדים עם פרימיטיבים, זה נקרא המרה אוטומטית. בדרך אחרת זה נקרא הרחבה. הנה דוגמה פשוטה של ​​הרחבה:
public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       byte littleNumber = 16;

       bigNumber = littleNumber;
       System.out.println(bigNumber);
   }
}
כאן אנו מקצים ערך byteלמשתנה int. המטלה הצליחה וללא כל בעיות: הערך המאוחסן בתופס byteפחות שטח זיכרון ממה שהוא "מתאים" ל int. "בובת קינון קטנה" (ערך byte) משתלבת בקלות ב"מטריושקה הגדולה" (משתנה int). זה עניין אחר כשאתה מנסה לעשות את ההפך - הכנס ערך גדול למשתנה שאינו מיועד לגדלים כאלה. באופן עקרוני, הטריק הזה לא יעבוד עם בובות קינון אמיתיות, אבל בג'אווה זה יעבוד, אלא עם ניואנסים. בואו ננסה להכניס ערך intלמשתנה short:
public static void main(String[] args) {

   int bigNumber = 10000000;

   short littleNumber = 1000;

   littleNumber = bigNumber;//error!
   System.out.println(bigNumber);
}
שְׁגִיאָה! המהדר מבין שאתה מנסה לעשות משהו לא סטנדרטי, ושם בובת מטריושקה גדולה ( int) בתוך בובת קטנה ( short). שגיאת קומפילציה במקרה זה היא אזהרה מהמהדר: " היי, אתה בטוח שאתה רוצה לעשות את זה? "אם אתה בטוח, ספר על זה למהדר: " הכל בסדר, אני יודע מה אני עושה!" תהליך זה נקרא המרה מסוג מפורש, או צמצום . כדי לבצע צמצום, עליך לציין במפורש את הסוג שאליו אתה רוצה להטיל את הערך שלך. במילים אחרות, ענה על השאלה של המהדר: " ובכן, באיזו מהבובות הקטנות האלה אתה רוצה לשים את הבובה הגדולה הזו?" "במקרה שלנו זה ייראה כך:
public static void main(String[] args) {

   int bigNumber = 10000000;

   short littleNumber = 1000;

   littleNumber = (short) bigNumber;
   System.out.println(littleNumber);
}
ציינו במפורש שאנחנו רוצים להתאים את הערך intלמשתנה shortולקחת עליו אחריות. המהדר, רואה אינדיקציה מפורשת של סוג צר יותר, מבצע המרה. מה תהיה התוצאה? פלט קונסולה: -27008 קצת לא צפוי. למה בדיוק ככה? זה בעצם פשוט. היה לנו את הערך המקורי - 10000000 הוא נשמר במשתנה intשתפס 32 סיביות, ובצורה בינארית הוא נראה כך: הרחבה והתכווצות של טיפוסים פרימיטיביים - 3 אנחנו כותבים את הערך הזה למשתנה short, אבל הוא יכול לאחסן רק 16 סיביות! בהתאם לכך, רק 16 הסיביות הראשונות של המספר שלנו יועברו לשם, השאר יימחקו. כתוצאה מכך, המשתנה shortיכיל את הערך הרחבה והתכווצות של טיפוסים פרימיטיביים - 4, שבצורה עשרונית שווה בדיוק ל-27008. לכן המהדר "ביקש אישור" בצורה של ליהוק מפורש לסוג מסוים. ראשית, זה מראה שאתה לוקח אחריות על התוצאה, ושנית, זה אומר למהדר כמה מקום להקצות בעת יציקת סוגי. הרי אם בדוגמה האחרונה היינו מטילים intל-type byte, ולא ל- short, היו עומדים לרשותנו רק 8 ביטים, לא 16, והתוצאה הייתה שונה. עבור סוגי שברים ( floatו double), הצמצום מתרחש בצורה שונה. אם תנסה להמיר מספר כזה לסוג של מספר שלם, החלק השברי שלו יימחק.
public static void main(String[] args) {

   double d = 2.7;

   long x = (int) d;
   System.out.println(x);
}
פלט מסוף: 2

סוג נתונים char

אתה כבר יודע שסוג התווים משמש להצגת תווים בודדים.
public static void main(String[] args) {

   char c = '!';
   char z = 'z';
   char i = '8';

}
אבל יש לו מספר תכונות שחשוב להבין. בואו נסתכל שוב על הטבלה עם טווחי ערכים:
סוג פרימיטיבי גודל בזיכרון טווח ערכים
בייט 8 ביט -128 עד 127
קצר 16 ביט -32768 עד 32767
לְהַשְׁחִיר 16 ביט מ-0 ל-65536
int 32 ביטים מ-2147483648 ל-2147483647
ארוך 64 ביטים מ-9223372036854775808 ל-9223372036854775807
לָצוּף 32 ביטים מ-(2 בחזקת -149) ל-((2-2 בחזקת -23)*2 בחזקת 127)
לְהַכפִּיל 64 ביטים מ-(-2 בחזקת 63) ל-((2 בחזקת 63)-1)
בוליאני 8 (בשימוש במערכים), 32 (בשימוש בלא-מערכים) אמת או שקר
לסוג charיש טווח מספרי מ-0 עד 65536. אבל מה זה אומר? אחרי הכל, charאלה לא רק מספרים, אלא גם אותיות, סימני פיסוק... העובדה היא שהערכים charמאוחסנים ב-Java בפורמט Unicode. כבר נתקלנו ביוניקוד באחת ההרצאות הקודמות. אתם בוודאי זוכרים ש- Unicode הוא תקן קידוד תווים הכולל תווים כמעט מכל השפות הכתובות בעולם. במילים אחרות, זוהי רשימה של קודים מיוחדים שבהם יש קוד כמעט לכל תו מכל שפה. טבלת Unicode הכללית גדולה מאוד וכמובן שאין צורך ללמוד אותה בעל פה. הנה, למשל, חלק ממנו: התרחבות והתכווצות של טיפוסים פרימיטיביים - 5 העיקר הוא להבין את העיקרון של אחסון ערכים char, ולזכור כי לדעת את הקוד של סמל מסוים, אתה תמיד יכול לקבל אותו בתוכנית. בוא ננסה את זה עם מספר אקראי:
public static void main(String[] args) {

   int x = 32816;

   char c = (char) x ;
   System.out.println(c);
}
פלט מסוף: 耰 זהו הפורמט שבו תווים מאוחסנים ב-Java char. כל תו מתאים למספר - קוד מספרי של 16 סיביות, או שני בתים. Unicode 32816 מתאים לתו 耰. שימו לב לרגע הזה. בדוגמה זו השתמשנו במשתנה int. הוא תופס 32 סיביות של זיכרון , בעוד char16 . כאן בחרנו כי המספר שאנו צריכים, 32816, הוא מחוץ לטווח . למרות שהגודל , כמו קצר, הוא 16 סיביות, אין מספרים שליליים בטווח, כך שהטווח ה"חיובי" גדול פי שניים (65536 במקום 32767 ). אנחנו יכולים להשתמש ב-, כל עוד הקוד שלנו נופל בטווח של 65536. אבל אם ניצור מספר , הוא יתפוס יותר מ-16 סיביות. וכאשר מצמצמים את הסוגים: intshortcharcharcharshortintint >65536
char c = (char) x;
הסיביות הנוספות יימחקו, והתוצאה תהיה די בלתי צפויה.

תכונות של תוספת של char ושלמים

בואו נסתכל על דוגמה יוצאת דופן זו:
public class Main {

   public static void main(String[] args) {

      char c = '1';

      int i = 1;

       System.out.println(i+c);
   }
}
פלט מסוף: 50 O_O איפה ההיגיון? 1+1, מאיפה הגיעו 50?! אתה כבר יודע שערכים charמאוחסנים בזיכרון כמספרים בטווח שבין 0 ל-65536, המייצגים את ה-Unicode של הדמות שלנו. הרחבה והתכווצות של טיפוסים פרימיטיביים - 6 אז הנה זה. כאשר אנו מבצעים חיבור charוסוג מספר שלם כלשהו charמומר למספר המתאים לו ביוניקוד. כאשר בקוד שלנו הוספנו 1 ו-'1', הסמל '1' הומר לקוד שלו, שהוא 49 (תוכלו לבדוק זאת בטבלה למעלה). לכן, התוצאה הפכה להיות שווה ל-50. בואו ניקח שוב את חברנו הוותיק -כדוגמה , וננסה להוסיף אותו עם מספר כלשהו.
public static void main(String[] args) {

   char c = '耰';
   int x = 200;

   System.out.println(c + x);
}
פלט קונסולה: 33016 כבר גילינו שמקביל לקוד 32816. וכאשר נוסיף את המספר הזה ו-200, נקבל בדיוק את התוצאה שלנו - 33016 :) מנגנון הפעולה, כפי שאתה יכול לראות, הוא די פשוט.
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION