الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

المؤشّرات في جافا

بدأه مصطفى 36a2 في 14 نوفمبر 2013 · 3 رد · 2,436 مشاهدة · في JavaSE
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

يقولون "من الأمور المميزة في جافا أنها تلغي المؤشرات" ولكن هذا بصراحة كلام بعيد كل البعد عن الدقة !
فكل الكائنات في جافا مؤشرات !!
بل إن الكلام الصحيح ... جافا لا تسمح للمستخدم بــ"عدم" استعمال المؤشرات ..

حتى أن كلمة كائن غير دقيقة ! إن الكائن موجود في مكان ما من الذاكرة أما ما نستخدمه فهو مؤشر إلى الكائن !
في نهاية هذه المشاركة .. أرجو أن أقنعك بأن تقول .. مؤشر للكائن بدل العبارة غير الدقيقة : كائن .
كيف نشرح عملية الإسناد بالشكل الــ"غير دقيق" :
عندما نقوم بإسناد كائن إلى كائن آخر باستخدام عملية الإسناد = .. فإن الكائنين يصبحان كائنا واحدا والتغييرات في أحدهما ستكون هي نفس التغييرات في الآخر لأن لهما نفس المكان في الذاكرة  
لماذا كل هذا اللف والدوران ؟ .. الكلام السليم هو ما يلي :
الكائن هو نفسه ولكن المؤشرين مختلفين إلى نفس الكائن ..
بعبارة أخرى  ... حتى تقوم بأخذ قيمة (أو قيم متغيرات ) الكائن .. فعليك إنشاء كائن جديد ثم نسخ القيم واحدا واحداً من الكائن القديم بنفس الطريقة (كل ما صادفت كائن داخل الكائن المطلوب نسخه تعيد نفس العلمية )
ببساطة هذه نفس الطريقة التي نسند بها المؤشرات للكائنات إلى بعضها البعض .. ونفس الطريقة التي نمرر فيها المؤشرات إلى التوابع ! (في اللغات التي تعترف باستخدام المؤشرات بشكل صريح )
فيما يلي مثال بسيط يبين تمرير الوسطاء والإسناد .. كيف أنه يتم باستخدام المرجعية (العنوان ) (المؤشرات :) )
طبعا قبل أن ندخل الى المثال يجب أن نعلم أن انواع البيانات الاساسية ليست كائنات وبالتالي ليست مؤشرات بل نتعامل معها مباشرة .. أي ان المتغير int x يدل على نفسه وليس على مؤشر يشير لعنوان آخر في الذاكرة يحوي عددا صحيحا
المثال هو كما يلي .. خطوة خطوة ..
ليكن لدينا الصف التالي :

class Ref
{
    public  int x=0;
    public  JButton B=new JButton("Hello");
    public int passX()
    {
        return x;
    }
    public JButton passB()
    {
        return B;
    }
    public void changeInt(int w)
    {
        w=5;
    }
    public void changeButton(JButton w)
    {
        w.setText("What is Your Name?");
    }
}
التابعان التاليان يعيد أحدهما قيمة x والآخر يعيد الكائن B ( والهدف من هذه المشاركة أن نعرف ما الذي يعيده بالضبط ؟ )
    public int passX()
    {
        return x;
    }
    public JButton passB()
    {
        return B;
    }
والتابعان الآخران يقومان بتغيير قيمة الوسيط الممرر ..
    public void changeInt(int w)
    {
        w=5;
    }
    public void changeButton(JButton w)
    {
        w.setText("What is Your Name?");
    }
    ملاحظة : استعملت كائن الزر JButton لأنه الأكثرشهرة في الكتب .. كلما أراد أحد التحدث عن كائن .. ذكر الأزرار كأوضح مثال .. ولكننا سنستخدم نص الزر فقط في المثال .
    والآن لنختبر الصف كما يلي :
    بداية لا ننسى كتابة :
    
    import javax.swing.JButton;


public class TestReference {
    public static void main(String[] args) {
    والآن لنبدأ
    نقوم ببناء كائن جديد .. والتأكد من القيم الأصلية للكائنات
    
            Ref R=new Ref();
        int outX=R.passX();            System.out.println(outX);
        JButton outB=R.passB();    System.out.println(outB.getText());
        لاحظ أن المتحول outX (يفترض) أن يحتفظ بقيمة المتحول x داخل الكائن R..  ولكن في مكان مختلف من الذاكرة (أي سيكون لدينا نسختان مختلفتا العنوان )
        كما أن المتحول outB (يفترض) أن يكون هو نفسه الكائن B داخل الكائن R .. طبعا كما ذكرت في البداية هذا الكلام غير دقيق لأن outB الآن هو مؤشر يحتفظ بعنوان الكائن ...( أبق هذا في ذهنك دائما )
        وسيكون الخرج كما هو متوقع :
        
        0        Hello
        والآن لنحاول أن نعدل على القيمة الصحيحة (وهي نوع أساسي وليست كائناً ) ثم نرى هل تغيرت القيمة داخل الكائن أو لا :
        
        
        outX=1;
        System.out.println(outX+ " " + R.passX());
        والخرج :
        
        1 0
    لا تغيير داخل الكائن .. التغيير فقط في المتحول الذي غيرناه ( كما هو متوقع )
    ماذا لو غيرنا الكائن outB :
    
        outB.setText("Shut Up !");
        System.out.println(outB.getText()+ " " + R.passB().getText());
    الخرج المفاجئ :
    
    Shut Up ! Shut Up !
    تغير الكائن B بداخل الكائن R رغم أننا غيرنا الكائن outB فقط !
    وهذا مصداق قولنا أننا نتعامل مع مؤشرين يؤشران لنفس الكائن وأن العملية = التي قمنا بها في البداية قامت بإسناد عناوين الذاكرة بين المؤشرين فقط لا غير ! لا يوجد نسخ للقيم ... وفي الذاكرة هناك مكان واحد يحتفظ بالكائن وليس مكانان مختلفان
    لنجرب تمرير الوسطاء :
    
            R.changeInt(outX);System.out.println(outX+ " " + R.passX());
        R.changeButton(outB);System.out.println(outB.getText()+ " " + R.passB().getText());
    ربما لن يفاجئك الآن الخرج التالي :
    
    1 0    What is Your Name? What is Your Name?
    القيمة الصحية تم تمريرها بـ(القيمة ) أي أن التابع changeInt تعامل مع نسخة لها مكان آخر في الذاكرة ..
    بينما تم تمرير الكائن بالمرجع (أي تم تمرير عنوان الكائن الذي سنتعامل معه ) بالتالي لم ننسخ نسخة أخرى ونعدل عليه بل عدلنا النسخة الوحيدة !
    
    أخيرا هذا مثال بسيط لتأكيد أن الإسناد هو إسناد لعنوان الكائن وليس لمحتوياته .. وبمجرد إسناد مؤشر لآخر .. ستفقد بيانات الكائن الأول من يؤشر إليها .. وسنترك لململم النفايات garbage collector مهمة تحرير مكانها من الذاكرة ..
    
        Ref q=new Ref();q.x=100;
        System.out.println(q);
        Ref w=new Ref();w.x=684;
        System.out.println(w);
        w=q;
        System.out.println(w.x);
        
        System.out.println(w);
        System.out.println(q);
    اقرأ الخرج بعناية وانتبه كيف أن طباعة كائن هي طباعة عنوانه .. تماماً لو كنا نطبع مؤشراً .. سنطبع قيمة العنوان الذي يؤشر إليه!
    
    Ref@a59698
    Ref@141d683
    100
    Ref@a59698
    Ref@a59698
    لاحظ كيف صار للمؤشرين القيمة ذاتها ... ولا أريد أن يقول أحد صار للكائنين العنوان ذاته ..
    لنتوقف عن قول كائنات .. ولنقل مؤشرات للكائنات .. فليس من المنطق نسف الدقة من أجل اختصار الكلام ..
    
    والحمد لله رب العالمين
2
#2

لقد إستمتعت بقراءة المفالة، في ملف الـ txt، شكراً لك على المعلومات المفيدة، :D  لقد أبعدت عني الكثير من اللبس والشكوك التي كانت تدور ببالي حول الجافا وطريقة تعاملها مع الكائنات B) ، خاصة وأنك تجد في أغلب المصادر أن لايوجد شيئ في الجافا يسمى Pointer، لكن الحقيقة،

there is no need for pointer, because actually, everything is a pointer، 

1
#3

آلة الجافا مكتوبة بلغة السي لذلك فكل ما يحدث في السي يحدث في الجافا ومعنى ذلك أن الجافا تتعامل مع المؤشرات كما في السي غير ان ذلك متروك لآلة الجافا JRE ولجامع النفايات

 

ومع ذلك فقد أتاحت لنا الجافا بعض أدوات التعامل مع الذاكرة مثل الدالة close التي نجدها في كلاسات كثير مثل كلاسات IO

 

قرأت لأحد الخبراء يشدد فيها على عدم الاعتماد على جامع النفايات في تحرير الذاكرة بل لا بد أن يعود المبرمج نفسه على تحرير الذاكرة يدويا بالدالة close

1

vVIfFr.gif

مدونتي



إذا رأيتموني غبت فأطلت الغياب فربما أكون قد انتقلت عن الدنيا إلى الآخرة

فما أحوجني إلى دعوة صالحة من أخ لي كريم

 

http://www.tvquran.com/

 

LoGeCom

أول برنامج عربي للمحاسبة والتجارة وإدراة المخازن يعمل على اللينكس والماك والويندوز 

#4

لا يوجد في الجافا بوينترز ولكن يوجد  references  :)

مواضيع مشابهة