ערך מעבר לפי מנגנון מעבר פרמטר בג'אווה

1. הקדמה

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

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

2. מעבר לפי ערך לעומת הפניה דרך מעבר

נתחיל בכמה מהמנגנונים השונים להעברת פרמטרים לפונקציות:

  • ערך
  • התייחסות
  • תוֹצָאָה
  • ערך-תוצאה
  • שֵׁם

שני המנגנונים הנפוצים ביותר בשפות התכנות המודרניות הם "Pass-by-Value" ו- "Pass-by-Reference". לפני שנמשיך, נדון בהתחלה:

2.1. ערך מעבר

כאשר פרמטר הוא ערך מעבר, המתקשר ושיטת callee פועלים על שני משתנים שונים שהם עותקים זה מזה. כל שינוי במשתנה אחד אינו משנה את השני.

זה אומר שבעוד שקוראים לשיטה, פרמטרים המועברים לשיטת callee יהיו שיבוטים של פרמטרים מקוריים. כל שינוי שנעשה בשיטת callee לא ישפיע על הפרמטרים המקוריים בשיטת המתקשר.

2.2. עובר דרך הפניה

כאשר פרמטר הוא הפניה דרך מעבר, המתקשר וה- callee פועלים על אותו אובייקט.

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

3. העברת פרמטר בג'אווה

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

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

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

בואו נראה את זה בפעולה בעזרת כמה דוגמאות קוד.

3.1. העברת סוגים פרימיטיביים

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

אורך החיים של הפרמטרים הפורמליים הללו נמשך רק כל עוד שיטה זו פועלת, וכאשר חוזרים, הטיעונים הפורמליים הללו מוסרים מהערימה ונמחקים.

בואו ננסה להבין את זה בעזרת דוגמה לקוד:

Class class PrimitivesUnitTest {@Test public void whenModifyingPrimitives_thenOriginalValuesNotModified () {int x = 1; int y = 2; // לפני השינוי assertEquals (x, 1); assertEquals (y, 2); שנה (x, y); // לאחר השינוי assertEquals (x, 1); assertEquals (y, 2); } שינוי ריק סטטי ציבורי (int x1, int y1) {x1 = 5; y1 = 10; }} 

בואו ננסה להבין את הטענות בתוכנית לעיל על ידי ניתוח האופן שבו ערכים אלה נשמרים בזיכרון:

  1. המשתנים “איקס" ו"y ” בשיטה העיקרית הם סוגים פרימיטיביים וערכיהם נשמרים ישירות בזיכרון הערימה
  2. כשאנחנו קוראים לשיטה לְשַׁנוֹת(), עותק מדויק לכל אחד מהמשתנים הללו נוצר ומאוחסן במיקום אחר בזיכרון הערימה
  3. כל שינוי בעותקים אלה משפיע רק עליהם ומשאיר את המשתנים המקוריים ללא שינוי

3.2. העברת הפניות לאובייקט

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

אובייקט Java, בניגוד ל- Primitives, מאוחסן בשני שלבים. משתני ההתייחסות מאוחסנים בזיכרון הערימה והאובייקט אליו הם מתייחסים נשמר בזיכרון Heap.

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

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

בואו ננסה להבין זאת בעזרת דוגמת קוד:

class class NonPrimitivesUnitTest {@Test public void whenModifyingObjects_thenOriginalObjectChanged () {Foo a = Foo new (1); Foo b = Foo חדש (1); // לפני השינוי assertEquals (a.num, 1); assertEquals (b.num, 1); לשנות (א, ב); // לאחר השינוי assertEquals (a.num, 2); assertEquals (b.num, 1); } שינוי ריק סטטי ציבורי (Foo a1, Foo b1) {a1.num ++; b1 = Foo חדש (1); b1.num ++; }} class Foo {public int num; Foo ציבורי (int num) {this.num = num; }}

בואו ננתח את הטענות בתוכנית לעיל. עברנו חפצים א ו ב ב לְשַׁנוֹת() שיטה בעלת ערך זהה 1. בתחילה, הפניות לאובייקט אלה מצביעות על שני מיקומי אובייקט מובחנים במרחב הערימה:

כאשר הפניות הללו א ו ב מועברים ב לְשַׁנוֹת() השיטה, היא יוצרת עותקי מראה של אותם הפניות a1 ו b1 המצביעים על אותם חפצים ישנים:

בתוך ה לְשַׁנוֹת() כאשר אנו משנים את ההתייחסות a1, זה משנה את האובייקט המקורי. עם זאת, לצורך התייחסות b1, הקצנו אובייקט חדש. אז זה מצביע כעת על אובייקט חדש בזיכרון הערימה.

כל שינוי שנעשה ב b1 לא ישקף דבר באובייקט המקורי:

4. מסקנה

במאמר זה בדקנו כיצד מטפלים בהעברת פרמטרים במקרה של פרימיטיבים ולא פרימיטיבים.

למדנו שהעברת פרמטר בג'אווה היא תמיד Pass-by-Value. עם זאת, ההקשר משתנה תלוי אם עסקינן בפרימיטיבים או אובייקטים:

  1. עבור סוגים פרימיטיביים, הפרמטרים הם ערך מעבר
  2. עבור סוגי אובייקטים, הפניה לאובייקט היא ערך מעבר

קטעי הקוד המשמשים במאמר זה ניתן למצוא באתר GitHub.


$config[zx-auto] not found$config[zx-overlay] not found