المقدمة
يشكك العديد من مبرمجي جافا ما إذا كانت جافا تعتمد على القيمة أم على الإشارة. يلخص هذا المقال الأسباب التي تجعل جافا دائماً تعتمد على القيمة.
أولاً، ماذا تعني القيمة والإشارة؟
- التمرير بالقيمة: قيم المعاملات الأساسية يتم نسخها إلى متغير آخر، ثم يتم تمرير الكائن المنسوخ إلى الطريقة. الطريقة تستخدم النسخة.
- التمرير بالإشارة: يتم تمرير اسم مستعار أو إشارة إلى المعامل الفعلي إلى الطريقة. الطريقة تصل إلى المعامل الفعلي.
غالبًا ما تكون الالتباس حول هذه المصطلحات ناتجة عن مفهوم مرجع الكائن في جافا. من الناحية الفنية، جافا تعتمد دائمًا على القيمة، لأنه حتى لو كانت المتغير قد يحتوي على إشارة إلى كائن، إلا أن إشارة هذا الكائن هي قيمة تمثل موقع الكائن في الذاكرة. وبالتالي، يتم تمرير مراجع الكائن بقيمة.
كل من أنواع البيانات المرجعية وأنواع البيانات الأساسية تتم نسخها بالقيمة. تعرف أكثر على أنواع البيانات في جافا.
بالإضافة إلى فهم أنواع البيانات، من المهم أيضًا فهم تخصيص الذاكرة في جافا، لأن أنواع البيانات المرجعية والأساسية تخزن بشكل مختلف.
عرض تمرير القيمة
المثال التالي يوضح كيفية تمرير القيم في لغة البرمجة جافا.
يستخدم البرنامج المثالي الصف التالي:
public class Balloon {
private String color;
public Balloon() {}
public Balloon(String c) {
this.color = c;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
البرنامج المثالي التالي يستخدم طريقة عامة، swap()
، التي تقوم بتبديل قيمتين. وتحاول الطريقة الأخرى، changeValue()
، تغيير قيم المتغيرات.
public class Test {
public static void main(String[] args) {
Balloon red = new Balloon("Red"); // مرجع الذاكرة = 50
Balloon blue = new Balloon("Blue"); // مرجع الذاكرة = 100
swap(red, blue);
System.out.println("After the swap method executes:");
System.out.println("`red` color value = " + red.getColor());
System.out.println("`blue` color value = " + blue.getColor());
changeValue(blue);
System.out.println("After the changeValue method executes:");
System.out.println("`blue` color value = " + blue.getColor());
}
// الطريقة العامة للتبديل
public static void swap(Object o1, Object o2){
Object temp = o1;
o1 = o2;
o2 = temp;
}
private static void changeValue(Balloon balloon) { // balloon = 100
balloon.setColor("Red"); // balloon = 100
balloon = new Balloon("Green"); // balloon = 200
balloon.setColor("Blue"); // balloon = 200
}
}
عند تنفيذ البرنامج المثالي، تحصل على الناتج التالي:
OutputAfter the swap method executes:
'red' color value = Red
'blue' color value = Blue
After the changeValue method executes:
'blue' color value = Red
يظهر الناتج أن طريقة swap()
لم تقم بتبديل قيم الألوان للكائنات الأصلية. وهذا يساعد في إظهار أن لغة البرمجة جافا تمرر القيمة، حيث تعمل طريقة swap()
فقط على نسخ من قيم مراجع الكائن الأصلي.
يمكن استخدام اختبار طريقة swap()
هذا مع أي لغة برمجة للتحقق مما إذا كانت تمرر القيمة أم تمرر المرجع.
تم شرح مثال الطريقة swap()
عند استخدام مشغل new
لإنشاء مثيل من فئة، يتم إنشاء الكائن والمتغير يحتوي على الموقع في الذاكرة حيث يتم حفظ الكائن.
Balloon red = new Balloon("Red");
Balloon blue = new Balloon("Blue");
وفيما يلي عرض تفصيلي خطوة بخطوة لما يحدث عند تنفيذ الطريقة swap()
:
-
لنفترض أن
red
يشير إلى موقع الذاكرة 50 وblue
يشير إلى موقع الذاكرة 100، وأن هذه هي مواقع الذاكرة لكائنيBalloon
كلاهما. -
عندما يقوم الفصيلة باستدعاء الطريقة
swap()
مع المتغيراتred
وblue
كمعلمات، يتم إنشاء متغيرات كائن جديدة،o1
وo2
.o1
وo2
أيضًا يشيران إلى مواقع الذاكرة 50 و 100 على التوالي. -
توضح مقاطعة الشفرة التالية ما يحدث داخل طريقة
swap()
:public static void swap(Object o1, Object o2) { // o1 = 50, o2 = 100 Object temp = o1; // تعيين قيمة مرجع الكائن لـ o1 إلى temp: temp = 50، o1 = 50، o2 = 100 o1 = o2; // تعيين قيمة مرجع الكائن لـ o2 إلى o1: temp = 50، o1 = 100، o2 = 100 o2 = temp; // تعيين قيمة مرجع temp إلى o2: temp = 50، o1 = 100، o2 = 50 } // انتهت الطريقة
-
قيم o1 و o2 تم استبدالها، ولكن نظرًا لأن القيم هي نسخ من مواقع الذاكرة للأحمر والأزرق، فليس هناك تغيير في قيم الأحمر والأزرق.
نظرًا لأن المتغيرات تحتوي على المرجع إلى الكائنات، من الخطأ الشائع أن نفترض أنك تمرر المرجع وأن جافا تمرر بالمرجع. ومع ذلك، أنت تمرر قيمة هي نسخة من المرجع وبالتالي فإنها تمرر بالقيمة.
شرح مثال طريقة changeValue()
private static void changeValue(Balloon balloon) { // البالون = 100
balloon.setColor("Red"); // البالون = 100
balloon = new Balloon("Green"); // البالون = 200
balloon.setColor("Blue"); // البالون = 200
}
الطريقة التالية في البرنامج المثال تغير قيمة اللون للكائن المشار إليه بواسطة متغير blue
:
-
تقوم الفئة باستدعاء طريقة
changeValue()
على المتغيرblue
الذي يشير إلى موقع الذاكرة 100. السطر الأول ينشئ مرجعًا يشير أيضًا إلى موقع الذاكرة 100. يتم تغيير قيمة اللون للكائن في موقع الذاكرة 100 إلى"أحمر"
. -
السطر الثاني ينشئ كائنًا جديدًا (بقيمة للون
"أخضر"
). الكائن الجديد في موقع الذاكرة 200. أي طرق تُنفذ على متغيرballoon
بعد ذلك تؤثر على الكائن في موقع الذاكرة 200، ولا تؤثر على الكائن في موقع الذاكرة 100. يعوض المتغير الجديدballoon
المرجع الذي تم إنشاؤه في السطر 1، والمرجعballoon
من السطر 1 لم يعد قابلًا للوصول في هذه الطريقة. -
السطر الثالث يغير قيمة اللون للكائن الجديد
Balloon
في موقع الذاكرة 200 إلى"Blue"
، ولكن لا يؤثر على الكائن الأصلي الذي يشير إليهblue
في موقع الذاكرة 100. وهذا يفسر لماذا تطبع السطر النهائي من إخراج برنامج المثالblue color value = Red
، مما يعكس التغيير من السطر 1.
الختام
في هذا المقال تعلمت عن سبب تمرير Java بالقيمة. استمر في تعلمك مع المزيد من دروس Java.
Source:
https://www.digitalocean.com/community/tutorials/java-is-pass-by-value-and-not-pass-by-reference