חפצים ומערכים

ברוך הבא למהדורה נוספת של Under The Hood . טור זה מתמקד בטכנולוגיות הבסיסיות של Java. מטרתו לתת למפתחים הצצה למנגנונים שגורמים לתוכניות הג'אווה שלהם לפעול. במאמר החודש מתבוננים בקודי הבייט העוסקים בחפצים ומערכים.

מכונה מונחה עצמים

המכונה הווירטואלית של Java (JVM) עובדת עם נתונים בשלוש צורות: אובייקטים, הפניות לאובייקטים וסוגים פרימיטיביים. חפצים שוכנים על ערמת האשפה. הפניות לאובייקטים וסוגים פרימיטיביים נמצאים בערמת Java כמשתנים מקומיים, בערימה כמשתנים למשל של אובייקטים, או באזור השיטה כמשתני מחלקה.

במכונה הווירטואלית של Java, זיכרון מוקצה בערימה שנאספה אשפה רק כאובייקטים. אין דרך להקצות זיכרון לסוג פרימיטיבי בערימה, אלא כחלק מאובייקט. אם ברצונך להשתמש בסוג פרימיטיבי במקום בו Objectיש צורך בהפניה, תוכל להקצות אובייקט עטיפה מהסוג java.langמהחבילה. לדוגמא, יש Integerמחלקה שעוטפת intסוג עם אובייקט. רק הפניות לאובייקטים וסוגים פרימיטיביים יכולים להימצא על ערימת Java כמשתנים מקומיים. אובייקטים לעולם אינם יכולים להישאר על ערימת Java.

ההפרדה האדריכלית של אובייקטים וסוגים פרימיטיביים ב- JVM באה לידי ביטוי בשפת התכנות Java, בה לא ניתן להכריז על אובייקטים כמשתנים מקומיים. ניתן להכריז על כך רק הפניות לאובייקטים. עם ההצהרה, הפניה לאובייקט אינה מתייחסת לכלום. רק לאחר האתחול המפורש של ההתייחסות - או עם התייחסות לאובייקט קיים או עם קריאה אליו new- ההתייחסות מתייחסת לאובייקט ממשי.

במערך ההוראות של JVM, כל האובייקטים מיוצרים וניגשים אליהם באותה סט אופקודים, למעט מערכים. בג'אווה, מערכים הם אובייקטים מן המניין, וכמו כל אובייקט אחר בתוכנית ג'אווה, הם נוצרים באופן דינמי. ניתן להשתמש בהפניות מערך בכל מקום שמתבקש להפנות לסוג Object, ולהפעיל כל שיטה Objectבמערך. עם זאת, במכונה הווירטואלית של ג'אווה מטפלים במערכים באמצעות קודי בתים מיוחדים.

כמו בכל אובייקט אחר, לא ניתן להכריז על מערכים כמשתנים מקומיים; רק הפניות למערך יכולות. אובייקטים של מערך עצמם מכילים תמיד מערך של סוגים פרימיטיביים או מערך של הפניות לאובייקטים. אם אתה מצהיר על מערך אובייקטים, מתקבל מערך של הפניות לאובייקטים. יש ליצור את האובייקטים עצמם במפורש newולהקצותם לאלמנטים של המערך.

Opcodes לאובייקטים

ייצוב של אובייקטים חדשים מתבצע באמצעות

new

אופקוד. שני אופרנדים של בת אחד עוקבים אחר

new

אופקוד. שני בתים אלה משולבים ליצירת אינדקס של 16 סיביות למאגר הקבוע. אלמנט הבריכה הקבוע בקיזוז שצוין נותן מידע על מחלקת האובייקט החדש. ה- JVM יוצר מופע חדש של האובייקט בערמה ודוחף את ההתייחסות לאובייקט החדש אל הערימה, כמוצג להלן.

יצירת אובייקטים
אופקוד אופרנדים תיאור
new indexbyte1, indexbyte2 יוצר אובייקט חדש בערימה, דוחף התייחסות

הטבלה הבאה מציגה את קוד הקודים שמציבים ומקבלים שדות אובייקט. קידודים אלה, putfield ו- getfield, פועלים רק על שדות שהם משתני מופע. למשתנים סטטיים ניתן לגשת באמצעות putstatic ו- getstatic, המתוארים בהמשך. הוראות הפוטפילד והגטפילד לוקחות כל אחת שני אופרנדים של בת אחד. האופרנדים משולבים ליצירת אינדקס של 16 סיביות למאגר הקבוע. פריט הבריכה הקבוע באותו אינדקס מכיל מידע על סוג השדה, גודל וקיזוזו. הפניה לאובייקט נלקחת מהערימה הן בהוראות putfield והן ב- getfield. הוראת ה- putfield לוקחת את הערך המשתנה של המופע מהערימה, וההוראה getfield דוחפת את ערך המשתנה של המופע שהוחזר אל הערימה.

גישה למשתני מופע
אופקוד אופרנדים תיאור
putfield indexbyte1, indexbyte2 שדה קבוע, המצוין באינדקס, של אובייקט לערך (שניהם נלקחים מהערימה)
getfield indexbyte1, indexbyte2 דוחף שדה, מסומן על ידי אינדקס, של אובייקט (נלקח מהערימה)

ניתן לגשת למשתני מחלקה באמצעות אופקודים getstatic ו- putstatic, כפי שמוצג בטבלה שלהלן. שניהם getstatic ו putstatic לוקחים שני אופרנדים של בת אחד, אשר משולבים על ידי JVM כדי ליצור קיזוז של 16 סיביות לא חתומות לבריכה הקבועה. פריט הבריכה הקבוע במיקום זה נותן מידע על שדה סטטי אחד של כיתה. מכיוון שאין אובייקט מסוים המשויך לשדה סטטי, אין התייחסות לאובייקט המשמשת לא גטסטית או פוטסטטית. ההוראה הפוטסטטית לוקחת את הערך להקצות מהערימה. ההוראה הגטסטית דוחפת את הערך שאוחזר אל הערימה.

גישה למשתני מחלקה
אופקוד אופרנדים תיאור
putstatic indexbyte1, indexbyte2 שדה קבוע, המצוין באינדקס, של אובייקט לערך (שניהם נלקחים מהערימה)
getstatic indexbyte1, indexbyte2 דוחף שדה, מסומן על ידי אינדקס, של אובייקט (נלקח מהערימה)

קידודי האופק שלהלן בודקים אם הפניה לאובייקט בחלקה העליון של הערימה מתייחסת למופע של המחלקה או הממשק שנוצר באינדקס על ידי האופרנדים העוקבים אחרי קוד הקוד. ההוראה של שידור הצ'ק זורקת CheckCastExceptionאם האובייקט אינו מופע של המחלקה או הממשק שצוינו. אחרת, צ'ק-אסט לא עושה דבר. הפניה של האובייקט נשארת בערימה והביצוע נמשך בהוראה הבאה. הוראה זו מבטיחה כי הצוותים בטוחים בזמן הריצה ומהווים חלק משמיכת האבטחה של ה- JVM.

ההוראה של מופע הקופץ את הפניה לאובייקט מראש הערימה ודוחפת נכון או לא נכון. אם האובייקט הוא אכן מופע של המחלקה או הממשק שצוינו, אז אמיתי נדחק אל הערימה, אחרת, שקר נדחק אל הערימה. ההוראה של מופע השימוש משמשת ליישום instanceofמילת המפתח של Java, המאפשרת למתכנתים לבדוק אם אובייקט הוא מופע של מחלקה או ממשק מסוימים.

סוג בדיקה
אופקוד אופרנדים תיאור
checkcast indexbyte1, indexbyte2 זורק את ClassCastException אם לא ניתן להטיל אובייקט על מחסנית למחלקה באינדקס
instanceof indexbyte1, indexbyte2 דחיפות נכון אם אובייקט ref על מחסנית הוא מופע של מחלקה באינדקס, אחרת דוחף שקר

קידודים למערכים

ייצוב מערכים חדשים מתבצע באמצעות קוד המפתח החדש, מערך חדש ומערך רב-מערכי. קוד המפתח החדש משמש ליצירת מערכים מסוגים פרימיטיביים שאינם הפניות לאובייקטים. הסוג הפרימיטיבי המסוים מוגדר על ידי אופרנד יחיד אחד בתא בעקבות קוד ה- array החדש. ההוראה למערך החדש יכולה ליצור מערכים עבור בתים, קצרים, צ'אר, אינט, ארוך, צף, כפול או בוליאני.

ההוראה במערך המיידי יוצרת מערך של הפניות לאובייקטים. שני אופרנדים של בית אחד עוקבים אחר קוד הקוד של המערך המשולב ומשולבים ליצירת אינדקס של 16 סיביות למאגר הקבוע. תיאור מחלקת האובייקט שעבורו יש ליצור את המערך נמצא במאגר הקבוע באינדקס שצוין. הוראה זו מקצה מקום למערך הפניות האובייקט ומאתחל את ההפניות ל- null.

ההוראה למערך רב-ממדי משמשת להקצאת מערכים רב-ממדיים - שהם פשוט מערכי מערכים - ויכולים להיות מוקצים בשימוש חוזר בהוראות המערך החדש והמערך החדש. ההוראה למולטי-סיביות פשוט דוחסת את קודי-הביצועים הדרושים ליצירת מערכים רב-ממדיים להוראה אחת. שני אופרנדים של בת אחד עוקבים אחר קוד האחסון הרב-ערוצי ומשולבים כך שיווצר אינדקס של 16 סיביות למאגר הקבוע. תיאור מחלקת האובייקט שעבורו יש ליצור את המערך נמצא במאגר הקבוע באינדקס שצוין. מיד לאחר שני האופרנדים של הבתים החד היוצרים את אינדקס הבריכה הקבוע הוא אופרנד של בת אחד שמציין את מספר הממדים במערך הרב מימדי הזה. הגדלים עבור כל מימד מוצגים מעל הערימה.הוראה זו מקצה מקום לכל המערכים הדרושים ליישום המערכים הרב ממדיים.

יצירת מערכים חדשים
אופקוד אופרנדים תיאור
newarray סוג אורך הקופץ, מקצה מערך חדש של סוגים פרימיטיביים מהסוג המצוין על ידי atype, דוחף אובייקט של מערך חדש
anewarray indexbyte1, indexbyte2 אורך הקופץ, מקצה מערך חדש של אובייקטים מהמחלקה המצוין על ידי indexbyte1 ו- indexbyte2, דוחף אובייקט ref של המערך החדש
multianewarray indexbyte1, indexbyte2, מידות קופץ לממדים מספר אורכי המערך, מקצה מערך רב מימדי חדש של מחלקה המצוין על ידי indexbyte1 ו- indexbyte2, דוחף objectref של מערך חדש

הטבלה הבאה מציגה את ההוראה שמוציאה רפרנס מערך מעל ראש הערימה ודוחפת את אורכו של אותו מערך.

קבלת אורך המערך
אופקוד אופרנדים תיאור
arraylength (אף אחד) קופץ אובייקטref של מערך, דוחף את האורך של אותו מערך

The following opcodes retrieve an element from an array. The array index and array reference are popped from the stack, and the value at the specified index of the specified array is pushed back onto the stack.

Retrieving an array element
Opcode Operand(s) Description
baload (none) pops index and arrayref of an array of bytes, pushes arrayref[index]
caload (none) pops index and arrayref of an array of chars, pushes arrayref[index]
saload (none) pops index and arrayref of an array of shorts, pushes arrayref[index]
iaload (none) pops index and arrayref of an array of ints, pushes arrayref[index]
laload (none) pops index and arrayref of an array of longs, pushes arrayref[index]
faload (none) pops index and arrayref of an array of floats, pushes arrayref[index]
daload (none) pops index and arrayref of an array of doubles, pushes arrayref[index]
aaload (none) pops index and arrayref of an array of objectrefs, pushes arrayref[index]

The next table shows the opcodes that store a value into an array element. The value, index, and array reference are popped from the top of the stack.

Storing to an array element
Opcode Operand(s) Description
bastore (none) pops value, index, and arrayref of an array of bytes, assigns arrayref[index] = value
castore (none) pops value, index, and arrayref of an array of chars, assigns arrayref[index] = value
sastore (none) pops value, index, and arrayref of an array of shorts, assigns arrayref[index] = value
iastore (none) pops value, index, and arrayref of an array of ints, assigns arrayref[index] = value
lastore (none) pops value, index, and arrayref of an array of longs, assigns arrayref[index] = value
fastore (none) pops value, index, and arrayref of an array of floats, assigns arrayref[index] = value
dastore (none) pops value, index, and arrayref of an array of doubles, assigns arrayref[index] = value
aastore (none) ערך קופץ, אינדקס ומערך של מערך של אובייקטים, מקצה מערך [אינדקס] = ערך

מערך תלת מימדי: הדמיית מכונה וירטואלית של Java

היישומון שלהלן מדגים מכונה וירטואלית של Java המבצעת רצף של קודני byt. רצף קוד הביצוע בסימולציה נוצר על ידי javacעבור initAnArray()השיטה של ​​המחלקה המוצגת להלן:

class ArrayDemo {סטטי בטל initAnArray () {int [] [] [] threeD = new int [5] [4] [3]; עבור (int i = 0; i <5; ++ i) {for (int j = 0; j <4; ++ j) {for (int k = 0; k <3; ++ k) {threeD [ i] [j] [k] = i + j + k; }}}}}

קודי ה- byt שנוצרו על ידי javacfor initAnArray()מוצגים להלן: