שתי משפחות: פרימיטיביים והפניות
לכל ערך ב-Java יש טיפוס, והטיפוס הזה שייך לאחת משתי משפחות. טיפוסים פרימיטיביים מחזיקים ערך גולמי ישירות: מספר, תו יחיד, או true/false. טיפוסי הפניה מחזיקים הפניה (מצביע) לאובייקט שנמצא במקום אחר בזיכרון: String, מערכים וכל מחלקה שאתם או הספריות מגדירים.
ההבחנה חשובה כי פרימיטיביים קלים ומועתקים לפי ערך, ואילו משתני הפניה מצביעים על אובייקטים משותפים. התחילו בשמונת הפרימיטיביים: הם הבסיס שכל השאר בנוי עליו.
שמונת הטיפוסים הפרימיטיביים
ל-Java יש בדיוק שמונה טיפוסים פרימיטיביים מובנים. שישה הם מספרים, אחד הוא תו ואחד הוא בוליאני:
כמה דברים ששווה לשים לב אליהם מראש: הקווים התחתונים ב-2_000_000 הם רק מפרידים ויזואליים שהקומפיילר מתעלם מהם, הסיומות L ו-f הן חובה (עוד על זה בהמשך), ו-char משתמש בגרשיים בודדים, ואילו String היה משתמש במירכאות כפולות.
בחירת טיפוס מספרי
כמעט אף פעם לא צריך byte או short: הם חוסכים זיכרון רק במערכים ענקיים. ההחלטות האמיתיות הן בין int/long למספרים שלמים לבין float/double לעשרוניים.
| טיפוס | גודל | מתי להשתמש |
|---|---|---|
int | 32 ביט | ברירת המחדל למספרים שלמים (עד בערך 2.1 מיליארד) |
long | 64 ביט | ערכים מעל בערך 2 מיליארד: חותמות זמן במילישניות, גדלי קבצים |
double | 64 ביט | ברירת המחדל לעשרוניים: דיוק טוב |
float | 32 ביט | רק כשהזיכרון מוגבל ואפשר לוותר על דיוק |
המלכודת היא גלישה (overflow). int מתגלגל בשקט כשהוא חורג מהטווח שלו: בלי שגיאה, רק תשובה שגויה:
maxInt + 1 גולש ל--2147483648 כי שני האופרנדים הם int והתוצאה נשארת int. המרה של אחד הצדדים ל-long קודם גורמת לחישוב להתבצע ב-64 ביט. כשערך עשוי להיות גדול, במיוחד מילישניות מאז 1970, בחרו ב-long.
ליטרלים והסיומות שלהם
לליטרל מספרי חשוף יש טיפוס ברירת מחדל, וזה מפיל אנשים. 100 הוא int; 3.14 הוא double. כדי לכתוב ליטרל long או float חייבים להוסיף סיומת:
אם תמחקו את ה-L מ-8_000_000_000L הקוד לא יתקמפל, כי הליטרל חורג מהטווח של int עוד לפני שהוא מגיע למשתנה ה-long. אם תמחקו את ה-f מ-0.5f, Java תתלונן שאי אפשר להשים double ל-float בלי המרה. הסיומת לא רגישה לאותיות גדולות וקטנות, אבל השתמשו ב-L גדולה: l קטנה נראית בדיוק כמו הספרה 1.
char הוא מספר בתחפושת
char שומר יחידת קוד Unicode של 16 ביט, כלומר הוא משמש גם כמספר שלם קטן בלי סימן. אפשר לעשות עליו חשבון ולהמיר הלוך ושוב עם cast:
זה שימושי לפעמים להזזת אותיות, אבל אל תסמכו על זה לטקסט: בשביל זה יש String. שימו לב ש-char משתמש בגרשיים בודדים ('A'); מירכאות כפולות ("A") יוצרות String של תו אחד, שזה טיפוס שונה לגמרי.
ערכי ברירת מחדל (והמלכודת של משתנים מקומיים)
שדות ואיברי מערך שלא מאתחלים מקבלים ערך ברירת מחדל הגיוני. אבל זה חל רק על שדות ותאי מערך: משתנים מקומיים לא מקבלים ערך ברירת מחדל, ושימוש באחד כזה לפני השמת ערך הוא שגיאת קומפילציה, לא הפתעה בזמן ריצה.
אם במקום זה הייתם כותבים int x; System.out.println(x); בתוך main, הקומפיילר היה דוחה את הקוד עם "variable x might not have been initialized". ההקפדה הזו היא יתרון: היא מונעת מכם לקרוא זבל. ערכי ברירת המחדל שכדאי לזכור: טיפוסים מספריים 0, boolean false, char '�', וכל טיפוס הפניה null.
הבא בתור: מחרוזות
String הוא טיפוס ההפניה שתיגעו בו הכי הרבה: טקסט, ערכים מחוברים, קלט מהמשתמש. הוא מתנהג אחרת מהפרימיטיביים שכאן: הוא אובייקט, הוא immutable, ולהשוואת מחרוזות יש מלכודות משלה. העמוד הבא עוסק בו.
שאלות נפוצות
כמה טיפוסי נתונים יש ב-Java?
ל-Java יש שמונה טיפוסים פרימיטיביים: byte, short, int, long, float, double, char ו-boolean. כל השאר, String, מערכים וכל אובייקט, הם טיפוסי הפניה. כך שמספר הפרימיטיביים המובנים קבוע על שמונה, ואילו טיפוסי ההפניה בלתי מוגבלים, כי אתם (והספריות) מגדירים מחלקות חדשות.
מה ההבדל בין int ל-long ב-Java?
שניהם מחזיקים מספרים שלמים, אבל int הוא 32 ביט (טווח של בערך ±2.1 מיליארד) ו-long הוא 64 ביט (טווח של בערך ±9.2 קווינטיליון). השתמשו ב-int כברירת מחדל; עברו ל-long כשערך יכול לעבור שני מיליארד: חותמות זמן במילישניות, גדלי קבצים, מונים גדולים. ליטרל long צריך את הסיומת L, למשל long big = 10000000000L;.
מה ערך ברירת המחדל של int ב-Java?
שדה מטיפוס int מקבל כברירת מחדל 0, אבל רק שדות ואיברי מערך מקבלים ערכי ברירת מחדל. long מקבל 0L, double מקבל 0.0, boolean מקבל false, char מקבל '\u0000', וכל טיפוס הפניה מקבל null. משתנים מקומיים לא מקבלים ערך ברירת מחדל בכלל: חייבים להשים להם ערך לפני השימוש, אחרת הקוד לא יתקמפל.