CodeGym /בלוג Java /Random-HE /הרחבה והצרה של טיפוסים פרימיטיביים
John Squirrels
רָמָה
San Francisco

הרחבה והצרה של טיפוסים פרימיטיביים

פורסם בקבוצה
היי! ככל שהתקדמת דרך CodeGym, נתקלת בטיפוסים פרימיטיביים פעמים רבות. להלן רשימה קצרה של מה שאנו יודעים עליהם:
  1. הם אינם אובייקטים ומייצגים ערך המאוחסן בזיכרון
  2. יש כמה סוגים
    • מספרים שלמים: בייט , קצר , int , ארוך
    • מספרי נקודה צפה (שברית) : צף וכפול
    • ערכים לוגיים: בוליאני
    • ערכים סמליים (לייצוג אותיות וספרות): 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 לוקח יותר מבייט . וארוך הוא יותר גדול מקצר. ניתן להשוות את כמות הזיכרון שתופסת הפרימיטיבים לבובות קינון רוסיות: הרחבה והצרה של טיפוסים פרימיטיביים - 2 לכל בובת קינון יש מקום פנוי בפנים. ככל שבובת הקינון גדולה יותר, כך יש יותר מקום. בובת קינון גדולה ( ארוכה ) תוכל להכיל בקלות אינט קטן יותר . זה מתאים בקלות ואתה לא צריך לעשות שום דבר אחר. בג'אווה, כאשר עובדים עם פרימיטיבים, זה נקרא המרה מרומזת. או במילים אחרות, זה נקרא הרחבה.

הרחבה ב-Java

הנה דוגמה פשוטה להמרה מתרחבת:
public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       byte littleNumber = 16;

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

   int bigNumber = 10000000;

   short littleNumber = 1000;

   littleNumber = bigNumber;// Error!
   System.out.println(bigNumber);
}
שְׁגִיאָה! המהדר מבין שאתה מנסה לעשות משהו לא נורמלי על ידי דחיפה של בובת קינון גדולה ( int ) בתוך בובת קטנה ( קצרה ). במקרה זה, שגיאת הקומפילציה היא אזהרה מהמהדר: "היי, האם אתה בטוח לחלוטין שאתה רוצה לעשות זאת?" אם אתה בטוח, אז אתה אומר למהדר: "הכל בסדר. אני יודע מה אני עושה!" תהליך זה נקרא המרה מסוג מפורש, או צמצום.

צמצום בג'אווה

כדי לבצע המרה מצמצמת, עליך לציין במפורש את הסוג שאליו ברצונך להמיר את הערך שלך. במילים אחרות, עליך לענות על שאלת המהדר: "ובכן, לאיזו מבובות הקינון הקטנות האלה אתה רוצה להכניס את בובת הקינון הגדולה הזו?" במקרה שלנו, זה נראה כך:
public static void main(String[] args) {

   int bigNumber = 10000000;

   short littleNumber = 1000;

   littleNumber = (short) bigNumber;
   System.out.println(littleNumber);
}
אנו מציינים במפורש שאנו רוצים להכניס int למשתנה קצר ושניקח את האחריות. כשראה שסוג צר יותר צוין במפורש, המהדר מבצע את ההמרה. מה התוצאה? פלט מסוף: -27008 זה היה קצת לא צפוי. למה בדיוק קיבלנו את זה? למעשה, הכל מאוד פשוט. במקור, הערך היה 10000000 זה אוחסן במשתנה int , שתופס 32 סיביות. זה הייצוג הבינארי שלו:
הרחבה והצרה של טיפוסים פרימיטיביים - 3
אנו כותבים את הערך הזה למשתנה קצר , שיכול לאחסן רק 16 סיביות! בהתאם לכך, רק 16 הסיביות הראשונות של המספר שלנו יועברו לשם. השאר יסולקו. כתוצאה מכך, המשתנה הקצר מקבל את הערך הבא
הרחבה והצרה של טיפוסים פרימיטיביים - 4
שבצורה עשרונית שווה ל-27008 לכן המהדר מבקש ממך "לאשר" על ידי ציון המרת צמצום מפורשת לסוג מסוים. ראשית, זה מראה שאתה לוקח אחריות על התוצאה. ושנית, זה אומר למהדר כמה מקום להקצות בעת ההמרה. אחרי הכל, בדוגמה האחרונה, אם היינו מקצים ערך int למשתנה בתים ולא ל- short , אז יהיו לנו רק 8 סיביות לרשותנו, לא 16, והתוצאה תהיה שונה. לסוגי שבר ( צף וכפול ) יש תהליך משלהם לצמצום המרות . אם תנסה להטיל מספר פלגי לסוג של מספר שלם, החלק השברי ימחק.
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 (אם לא בשימוש במערכים) אמת או שקר
הטווח 0 עד 65536 מצוין עבור סוג ה-char . אבל מה זה אומר? אחרי הכל, char לא מייצג רק מספרים, אלא גם אותיות, סימני פיסוק... העניין הוא שב-Java ערכי char מאוחסנים בפורמט Unicode. כבר נתקלנו ביוניקוד באחד השיעורים הקודמים. אתם בוודאי זוכרים ש-Unicode הוא תקן קידוד תווים הכולל את הסמלים של כמעט כל השפות הכתובות בעולם. במילים אחרות, זוהי רשימה של קודים מיוחדים המייצגים כמעט כל תו בכל שפה. כל טבלת Unicode גדולה מאוד, וכמובן, אין צורך ללמוד אותה בעל פה. הנה חלק קטן ממנו: הרחבה והצרה של טיפוסים פרימיטיביים - 5 העיקר להבין כיצד מאוחסנים תווים, ולזכור שאם אתה יודע את הקוד של דמות מסוימת, אתה תמיד יכול לייצר את הדמות הזו בתוכנית שלך. בוא ננסה עם מספר אקראי:
public static void main(String[] args) {

   int x = 32816;

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

תכונות מיוחדות של הוספת תווים ומספרים שלמים

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

   public static void main(String[] args) {

      char c = '1';

      int i = 1;

       System.out.println(i + c);
   }
}
פלט קונסולה: 50 O_О איך זה הגיוני? 1+1. מאיפה הגיעו ה-50?! אתה כבר יודע charשערכים מאוחסנים בזיכרון כמספרים בטווח שבין 0 ל-65536, ושמספרים אלו הם ייצוג Unicode של תו. הרחבה והצרה של טיפוסים פרימיטיביים - 6 כאשר אנו מוסיפים char וסוג של מספר שלם, ה- char מומר למספר Unicode המתאים. בקוד שלנו, כאשר הוספנו 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