Monday, May 22, 2017

জাভা পাস-বাই-রেফারেন্স নাকি পাস-বাই-ভ্যালু ॥ পাগলের প্রলাপ

সবার প্রথমে একটা গল্প বলি । মূল গল্পটি কাহলিল জিবরানের , আমি সংক্ষিপ্ত এবং নিজের মত করেই লিখছি ।
গল্পঃ কোন এক কালে ছোট্ট কোন এক দেশে সবাই অনেক সুখে শান্তিতে বসবাস করত । সেই দেশে একটা কুপ ছিল যার পানি ছিল সুশীতল এবং সুমিষ্ট । রাজ্যের রাজা-প্রজা সবাই সেই কুপের পানি পান করত । এক রাত্রে এক ডাইনি এসে ওই কুপে কয়েক ফোটা পানি মিশিয়ে মনে মনে কিছু মন্ত্র পাঠ করে বিড়বিড় করে বলল যে আগামিকাল সকালে এই কুপের পানি যে যে পান করবে সে সে উন্মাদ হয়ে যাবে । পরের দিন রাজ্যের সবাই সেই কুপ থেকে পানি পান করল কেবল রাজা আর প্রধান উজির ব্যাতীত । কিছুক্ষন পর দেখা গেল রাজ্যের সব প্রজা নিজেদের কাজ বাদ দিয়ে কানা-ঘুষা শুরু করল যে, "আমাদের রাজা আর উজির পাগল হয়ে গিয়েছে, রাজ্যে নতুন রাজা নির্বাচিত করতে হবে নাহলে রাজ্য অচল হয়ে যাবে" । তো এমন অবস্থা দেখে রাজামশাই চিন্তিত হয়ে উজিরকে ডেকে বললেন যে যাও ওই কুপ থেকে ২ গ্লাস পানি নিয়ে এসো রাজ পেয়ালায় করে । তারপর রাজা আর উজির সেই পানি পান করলেন । পরদিন সকালে দেখা গেল সব স্বাভাবিক এবং সব প্রজা বলা বলি করতে লাগল, যাক আমাদের রাজামশাইয়ের তন্দ্রা ফিরে এসেছে, এবার রাজ্য চলবে । যথারীতি সুখে শান্তিতে সবাই জীবন যাপন করতে লাগল ।

গল্পটি বলা এজন্যই যে আপাতত এই আর্টিকেল পড়ার সময় ধরে নিন আমি একজন পাগল । আর পাগলের কোন কথা বিশ্বাস করতে হয়না ।

যাইহোক মূল কথায় আসি । অন্যান্য প্রোগ্রামিং ল্যাঙ্গুয়েজ তো বটেই খোদ জাভা ডেভলপারদের মাঝেই কনফিউশন আছে যে জাভা কি পাস-বাই-রেফারেন্স নাকি পাস-বাই-ভ্যালু । স্ট্যাকওভারফ্লো এই লিংকে জাভার প্যারামিটার পাসিং নিয়ে বেশ সুন্দর করে কিছু কথা বার্তা বলা হয়েছে । মূল বিষয় যেটি সেটি হল অধিকাংশ ডেভলপারই এটা পড়ার পর কনফিউশনে ভুগবেন যে এতদিন যেটা জেনে এসেছেন যে জাভা পাস-বাই-রেফারেন্স কিন্তু এখানে বলা হচ্ছে পাস-বাই-ভ্যালু সেটা কি তবে ভুল !
আসলে এটা জানার আগে আমাদের জানতে হবে পাস-বাই-ভ্যালু এবং পাস-বাই-রেফারেন্স কি জিনিস । আবারো স্ট্যাকওভারফ্লো এর একটা লিংক হাতে ধরিয়ে দেই । এখানে খুব সুন্দর ভাবে বুঝিয়ে বলা হয়েছে যে রেফারেন্স আর ভ্যালু পাসিং কি । সংক্ষেপে বলতে গেলে, কোন একটা ভ্যারিয়েবলের ভ্যালু কোন একটি মেথডে/ফাংশনের মাঝে পাস করা হলে যদি উক্ত মেথডের মাঝে ওই প্যারামিটারের কোন চেঞ্জ করা হয় তবে যেখান থেকে কল করা হয়েছিল সেখানেও চেঞ্জ হয়ে যায় তবে সেটাকে বলে রেফারেন্স পাসিং । মানে একই মেমোরিকে আমরা আলাদা আলাদা জায়গা থেকে অ্যাক্সেস করছি কিন্তু চেঞ্জ হবে একই জায়গায় । এটা না হয়ে যাদি এমন হয় যে কোন মেথডের মাঝে কোন একটা ভ্যারিয়েবলকে পাস করলে উক্ত ভ্যারিয়েবলের মানটি কেবল মাত্র পাস হয়ে যাচ্ছে কিন্তু যে ভ্যারিয়েবলটি পাস করা হয়েছে তার সাথে সম্পর্ক ছিন্ন হয়ে যাচ্ছে তবে সেটাকে বলে পাস বাই ভ্যালু ।



এখন প্রশ্ন হল জাভাতে এই দুই রকম বিহেভিয়রই প্রেজেন্ট । তাহলে জাভা কি পাস বাই ভ্যালু নাকি পাস বাই রেফারেন্স , নাকি দুটিই, নাকি কোনটিই না ? এগুলা আমরা দেখব তার আগে আমরা দুটি উদাহরন দেখি যে কিভাবে জাভাতে দুটি বিহেভিয়রই প্রেজেন্ট ।

পাস বাই ভ্যালুঃ
public class ReferenceTest {

    private int x = 5;

    private void increment(int x) {
        x++;
        System.out.println("Incremented Value: " + x);
    }

    public static void main(String[] args) {

        ReferenceTest rt = new ReferenceTest();
        rt.increment(rt.x);
        System.out.println("Original Value: " + rt.x);
    }
}

আউটপুটঃ
Incremented Value: 6
Original Value: 5


ছোট্ট এই প্রোগ্রামটি রান করলে আমরা দেখতে পারব যে জাভা আসলে পাস বাই ভ্যালু । increment মেথডটির মাঝে ভেরিয়েবলের ভ্যালু পাস হয়েছে তবে সেটা কেবল ভ্যালুটুকুই । সেটার সাথে অরিজিনাল ভেরিয়েবলের সম্পর্ক ছিন্ন করে কেবল ভ্যালুটুকুই ।

পাস বাই রেফারেন্সঃ
class ReferredObject {

    private int id;

    public ReferredObject(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

public class ReferenceTest {

    private void increment(ReferredObject ro) {

        ro.setId(ro.getId() + 1);
        System.out.println("Incremented Value: " + ro.getId());
    }

    public static void main(String[] args) {

        ReferenceTest rt = new ReferenceTest();
        ReferredObject ro = new ReferredObject(5);
        rt.increment(ro);
        System.out.println("Original Value: " + ro.getId());
    }
}

আউটপুটঃ
Incremented Value: 6
Original Value: 6


উপরোক্ত ছোট্ট প্রোগ্রামটিতে দেখা যাচ্ছে যে আমরা ReferredObject ক্লাসের একটি অবজেক্টকে increment মেথডের মাঝে পাস করে উক্ত অবজেক্টের ভ্যালু চেঞ্জ করলে সেটা যেখান থেকে কল করা হয়েছিল সেখানেও চেঞ্জ হয়ে যাচ্ছে । তার মানে এটা পাস বাই রেফারেন্স । (পাগলে কি না বলে!!!)

এখন তো মহা সমস্যা । জাভা কি তাহলে পাস বাই রেফারেন্স , পাস বাই ভ্যালু, দুটিই একাসাথে নাকি কোনটিই না !

আসলে জাভা প্রিমিটিভের ক্ষেত্রে পাস বাই ভ্যালু এবং অবজেক্টের ক্ষেত্রে [জানিনা!!!] বিহেভিয়ার শো করে । মানে টা কি ! ফাজলামি নাকি !!

ওকে, সব কিছুর আগে আমাদের একটি বহুল ব্যাবহৃত কিওয়ার্ডের (new) কাজ সম্পর্কে ক্লিয়ার হয়ে নিতে হবে । 'new' কিওয়ার্ডের কাজ সম্পর্কে ওরাকলের টিউটোরিয়াল সিরিজে খুব সুন্দর চিত্র সহকারে ব্যাখ্যা করে বুঝিয়ে বলা হয়েছে । সংক্ষেপে বললে 'new' অপারেটর ছাড়া কোনভাবেই মেমোরিতে নতুন কোন স্পেস অ্যালোকেট করা সম্ভব নয় । কেবল মাত্র প্রিমিটিভ ভ্যারিয়েবল ছাড়া যেকোন অবজেক্ট এমনি অ্যারের ক্ষেত্রেও 'new' অপারেটর ব্যাবহার করতেই হবে মেমোরিতে নতুন স্পেস অ্যালোকেট করতে তথা নতুন অবজেক্ট ক্রিয়েট করতে । অন্য সব ক্ষেত্রে কেবল মাত্র একই অবজেক্টের লোকেশন পয়েন্টিং করা হবে আলাদা আলাদা নামে ।


কোডঃ
class ReferredObject {

    private int id;

    public ReferredObject(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

public class ReferenceTest {

    public static void main(String[] args) {

        ReferredObject ro1 = new ReferredObject(5);
        ReferredObject ro2 = ro1;
        ro2.setId(7);
        System.out.println("Value of ro2: " + ro2.getId());
        System.out.println("Value of ro1: " + ro1.getId());
    }
}

আউটপুটঃ
Value of ro2: 7
Value of ro1: 7

এই ছোট্ট প্রোগ্রামটিতে আমরা দেখতে পারছি যে 'ro1' অবজেক্টটি মেমোরিতে ক্রিয়েট হয়েছে কারন সেটাকে ক্রিয়েট করা হয়েছে 'new' অপারেটর এবং উক্ত ক্লাসের কনস্ট্রাক্টর ব্যাবহার করে, কিন্তু 'ro2' অবজেক্টরি মেমোরিতে নতুন কোন স্পেস অ্যালোকেট করে নি বরং 'ro1' যে মেমোরি স্পেসে রেফার করে ছিল ঠিক সেটাতেই রেফার করে আছে । এজন্য 'ro2' তে কোন প্রকার চেঞ্জ করা হলে সেটা ঠিক সেই মেমোরিকে ওভাররাইড করছে যে মেমোরি 'ro1' রেফার করে রয়েছে । ওকে , এবার তবে আমরা আরেকটা কোডে চলে যাই ।

কোডঃ
class ReferredObject {

    private int id;

    public ReferredObject(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

public class ReferenceTest {

    private void increment(ReferredObject ro, int newValue){
       
        ro.setId(newValue);
    }
   
    public static void main(String[] args) {

        ReferenceTest rt = new ReferenceTest();
        ReferredObject ro1 = new ReferredObject(5);
        ReferredObject ro2 = ro1;
        rt.increment(ro2, 11);
        System.out.println("Value of ro2: " + ro2.getId());
        System.out.println("Value of ro1: " + ro1.getId());
    }
}

আউটপুটঃ
Value of ro2: 11
Value of ro1: 11

উক্ত ছোট্ট প্রোগ্রামটি সব কিছু আগের মতই তবে এখানে ReferenceTest ক্লাসের মাঝে একটা মেথড increment অ্যাড করা হয়েছে যেটি ReferredObject টাইপের একটি প্যারামিটার এবং একটি ইন্টিজার ভ্যালু নেয় । যেহেতু increment মেথডের মাঝে পাস করার সময় আমরা ReferredObject কে নিউ দিয়ে ক্রিয়েট করিনি সেহেতু সে মেমোরিতে নতুন কোন স্পেস অ্যালোকেট করবে না বরং সেই মেমোরিকেই রেফার করবে যেটি 'ro1', 'ro2' করছে । অর্থাৎ 'ro1', 'ro2' এবং increment মেথডের 'ro' একই মেমোরি সেগমেন্টকে রেফার করে রয়েছে । যেকোন একটির মিউটেশন হলে সবগুলারই মিউটেশন হবে । এবার একটু ভিন্ন ধরনের একটা কোড দেখব আমরা ।

কোডঃ
class ReferredObject {

    private int id;

    public ReferredObject(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

public class ReferenceTest {

    private ReferredObject increment(ReferredObject ro, int newValue) {

        ro.setId(newValue);
        ro = new ReferredObject(newValue);
        ro.setId(ro.getId() + newValue);
        return ro;
    }

    public static void main(String[] args) {

        ReferenceTest rt = new ReferenceTest();
        ReferredObject ro1 = new ReferredObject(5);
        ReferredObject ro2 = ro1;
        ReferredObject ro3 = rt.increment(ro2, 11);
        System.out.println("Value of ro3: " + ro3.getId());
        System.out.println("Value of ro2: " + ro2.getId());
        System.out.println("Value of ro1: " + ro1.getId());
    }
}

আউটপুটঃ
Value of ro3: 22
Value of ro2: 11
Value of ro1: 11

উক্ত কোডটিও আগের মতই তবে এখানে কিছুটা পরিবর্তন করা হয়েছে । এখানে increment মেথডের মাঝে 'ro' এর মিউটেশন ততক্ষন 'ro1' এবং 'ro2' এর ক্ষেত্রেও প্রোযোজ্য হবে যতক্ষন পর্যন্ত তারা সেম রেফারেন্স পয়েন্ট করে থাকবে । যখনই 'ro' কে 'new' অপারেটর দিয়ে নতুন করে কনস্ট্রাক্ট করা হচ্ছে তখনই সেটা 'ro1' এবং 'ro2' থেকে ডিকাপলড হয়ে নতুন মেমোরি লোকেশনে রেফার করছে । এবং সেটার যেকোন মিউটেশন আর কোনভাবেই 'ro1' এবং 'ro2' তে প্রভাব বিস্তার করতে পারবে না ।

এবার অবজেক্টের মাঝে অবজেক্টের রেফারেন্স নিয়ে হালকা পাতলা কিছু কথা বলব ।
কোডঃ
class University {

    private String universityName;

    public University(String universityName) {
        this.universityName = universityName;
    }

    public String getUniversityName() {
        return universityName;
    }

    public void setUniversityName(String universityName) {
        this.universityName = universityName;
    }
}

class ReferredObject {

    private int id;
    private University university;

    public ReferredObject(int id, University university) {
        this.id = id;
        this.university = university;
    }

    public University getUniversity() {
        return university;
    }

    public void setUniversity(University university) {
        this.university = university;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

public class ReferenceTest {

    private ReferredObject increment(ReferredObject ro, int newValue) {

        ro.setId(newValue);
        ro = new ReferredObject(newValue, ro.getUniversity());
        ro.setId(ro.getId() + newValue);
        ro.getUniversity().setUniversityName("Changed University Name");
        return ro;
    }

    public static void main(String[] args) {

        ReferenceTest rt = new ReferenceTest();
        University university = new University("Universal University");
        ReferredObject ro1 = new ReferredObject(5, university);
        ReferredObject ro2 = ro1;
        ReferredObject ro3 = rt.increment(ro2, 11);
        System.out.println("Value of ro3: " + ro3.getId() + ", University Name: " + ro3.getUniversity().getUniversityName());
        System.out.println("Value of ro2: " + ro2.getId() + ", University Name: " + ro2.getUniversity().getUniversityName());
        System.out.println("Value of ro1: " + ro1.getId() + ", University Name: " + ro1.getUniversity().getUniversityName());
    }
}

আউটপুটঃ
Value of ro3: 22, University Name: Changed University Name
Value of ro2: 11, University Name: Changed University Name
Value of ro1: 11, University Name: Changed University Name

উপরোক্ত ছোট্ট উদাহরনটিতে আমরা দেখতে পারছি যে increment মেথডের মাঝে 'ro' কে নতুন করে কনস্ট্রাক্ট করা হয়েছে । তাই 'ro' , 'ro1' এবং 'ro2' থেকে ডিকাপলড হয়ে গিয়েছে । কিন্তু 'ro' এর মাঝে আমরা university এর সেই রেফারেন্সটিই রেফার করছি যেটি 'ro1' এবং 'ro2' তে রেফার হয়ে রয়েছে । সুতরাং 'ro' তে university এর যেকোন মিউটেশন 'ro1' এবং 'ro2' এর ক্ষেত্রেও প্রোযোজ্য হবে যদিনা আমরা 'ro' তে university কে 'new' কিওয়ার্ড দিয়ে নতুন করে কনস্ট্রাক্ট না করি ।

এমনকি থ্রেডের মাঝেও রেফারেন্স টাইপ একই বিহেভিয়ার শো করবে যেমনটা হওয়া কথা । মানে অবজেক্ট রেফারেন্সের একই যায়গায় ভ্যালু ওভাররাইড করবে । বোঝা না গেলে তার জন্য নিচের ছোট্ট একটু কোড দেখে ফেলুন ।

কোডঃ
class ReferredObject {

    private int id;

    public ReferredObject(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

class RefInThread implements Runnable {

    private final ReferredObject reffObject;
    private final long sleepingTime;
    private final int iteration;
    private final int threadId;

    public RefInThread(ReferredObject reffObject, long sleepingTime, int iteration, int id) {
        this.reffObject = reffObject;
        this.sleepingTime = sleepingTime;
        this.iteration = iteration;
        this.threadId = id;
    }

    @Override
    public void run() {

        try {

            for (int i = 0; i < this.iteration; i++) {

                Thread.sleep(this.sleepingTime);
                this.reffObject.setId(this.reffObject.getId() + 1);
                System.out.println("Changing in : " + this.threadId + ", Value: " + this.reffObject.getId());
            }
        } catch (InterruptedException e) {

            System.err.println(e.toString());
        }
    }
}

public class ReferenceTest {

    public static void main(String[] args) {

        ReferredObject ro = new ReferredObject(5);
        new Thread(new RefInThread(ro, 500, 10, 1)).start();
        new Thread(new RefInThread(ro, 800, 5, 2)).start();
    }
}

আউটপুটঃ
Changing in : 1, Value: 6
Changing in : 2, Value: 7
Changing in : 1, Value: 8
Changing in : 1, Value: 9
Changing in : 2, Value: 10
Changing in : 1, Value: 11
Changing in : 2, Value: 12
Changing in : 1, Value: 13
Changing in : 1, Value: 14
Changing in : 2, Value: 15
Changing in : 1, Value: 16
Changing in : 2, Value: 17
Changing in : 1, Value: 18
Changing in : 1, Value: 19
Changing in : 1, Value: 20

উপরোক্ত প্রোগ্রামটিতে থ্রেডের দুটি আলাদা আলাদা অবজেক্টের মাঝে প্যারামিটার হিসাবে একই রেফারেন্স পাস করা হয়েছে তাই তারা ওই রেফারেন্স পয়েন্টেই ভ্যালু ম্যানুপুলেট করবে , অর্থাৎ দুটি থ্রেডই আসলে একই অবজেক্ট নিয়ে কাজ করছে ।


এতক্ষন আপনার দেখলাম যতসব অবজেক্ট নিয়ে কথা বার্তা । প্রিমিটিভ ভ্যাল্যুর ক্ষেত্রে রেফারেন্সের উপায় তবে কি ? সেটার উত্তরের জন্য আবারো স্ট্যাকওভারফ্লোর এই লিংকটি ধরিয়ে দেই।

এবার কাজের কথায় আসি । জাভা কি পাস বাই রেফারেন্স নাকি পাস বাই ভ্যালু ? এতক্ষন আমরা যে উদাহরন গুলা দেখলাম সেটা যদি পাস বাই ভ্যালুর উদাহরন মনে হয় তবে জাভা পাস বাই ভ্যালু। আর যদি সেটা মনে না হয় তবে জাভা পাস বাই রেফারেন্স। এখন কথা হল জাভা যখন কোন একটি মেথডের প্যারামিটার হিসাবে কোন অবজেক্টকে রেফার করে তবে সেটা হয় কিভাবে । আমরা জানি প্রতিটি অবজেক্ট মেমোরিতে ক্রিয়েট হওয়ার সময় সেটা নির্দিষ্ট একটি মেমোরি লোকেশনে অ্যালোকেট হয় । JVM এই মেমোরি লোকেশন গুলাকে ম্যাপ করার জন্য হ্যাশ ভ্যালু ব্যাবহার করে । প্রতিটি অবজেক্ট যাদের 'new' অপারেটর দিয়ে ইন্সট্যান্সিয়েট করা হয় তার জন্য JVM একটি ইউনিক হ্যাশ কোড জেনারেট করে । ক্ষেত্র বিশেষে কিছু এক্সেপশনাল কন্ডিশন আসতে পারে যেটা অন্য কোন একটি আর্টিকেলে আলোচনা করা হবে । String ক্লাসও এই ধরনের ব্যাতীক্রম একটা ক্লাস । এগুলা নিয়ে অন্য কোন একদিন আলোচনা করা যাবে । এবার আমরা দেখি হ্যাশ কোড আসলে কিভাবে কাজ করছে ।

কোডঃ

class University {

    private String universityName;

    public University(String universityName) {
        this.universityName = universityName;
    }

    public String getUniversityName() {
        return universityName;
    }

    public void setUniversityName(String universityName) {
        this.universityName = universityName;
    }
}

class ReferredObject {

    private int id;
    private University university;

    public ReferredObject(int id, University university) {
        this.id = id;
        this.university = university;
    }

    public University getUniversity() {
        return university;
    }

    public void setUniversity(University university) {
        this.university = university;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

public class ReferenceTest {

    private ReferredObject increment(ReferredObject ro, int newValue) {

        ro.setId(newValue);
        ro = new ReferredObject(newValue, ro.getUniversity());
        ro.setId(ro.getId() + newValue);
        ro.getUniversity().setUniversityName("Changed University Name");
        return ro;
    }

    public static void main(String[] args) {

        ReferenceTest rt = new ReferenceTest();
        University university = new University("Universal University");
        ReferredObject ro1 = new ReferredObject(5, university);
        ReferredObject ro2 = ro1;
        ReferredObject ro3 = rt.increment(ro2, 11);
        System.out.println("Value of ro3: " + ro3.getId() + ", University Name: " + ro3.getUniversity().getUniversityName());
        System.out.println("Hash of ro3: " + ro3.hashCode() + ", Hash of university: " + university.hashCode());
        System.out.println("Value of ro2: " + ro2.getId() + ", University Name: " + ro2.getUniversity().getUniversityName());
        System.out.println("Hash of ro2: " + ro2.hashCode() + ", Hash of university: " + university.hashCode());
        System.out.println("Value of ro1: " + ro1.getId() + ", University Name: " + ro1.getUniversity().getUniversityName());
        System.out.println("Hash of ro1: " + ro1.hashCode() + ", Hash of university: " + university.hashCode());
    }
}

আউটপুটঃ

Value of ro3: 22, University Name: Changed University Name
Hash of ro3: 1808253012, Hash of university: 589431969
Value of ro2: 11, University Name: Changed University Name
Hash of ro2: 1252169911, Hash of university: 589431969
Value of ro1: 11, University Name: Changed University Name
Hash of ro1: 1252169911, Hash of university: 589431969

উপরোক্ত আউটপুটে আমরা দেখতে পারছি 'ro1' এবং 'ro2' এর হ্যাশ ভ্যালু একই কিন্তু 'ro3' এর হ্যাশ ভ্যালু আলাদা। 'ro1', 'ro2', এবং 'ro3' এর সবার ক্ষেত্রেই university এর হ্যাশ ভ্যালু একই । আসলে এই হ্যাশ ভ্যালুই হল JVM এর মেমোরি অ্যাড্রেসের টোকেন যে টোকেন দিয়ে JVM প্রতিটি অবজেক্টকে সিস্টেম মেমোরির সাথে ম্যাপ করে । যখন মেথডের মাধ্যমে কোন অবজেক্টকে পাস করা হয় তখন সেখানে এই হ্যাশ ভ্যালুই পাস হয় মেমোরি রেফারেন্স হিসাবে । যেহেতু রেফারেন্স হিসাবে একটা ভ্যালুকে পাস করা হচ্ছে তাই এটাকে পাস বাই ভ্যালু বলা যেতে পারে ।

আসলে জাভা যে কি সেটা বোধহয় খোদ ওরাকলও ভালোমত বলতে পারবে না সেখানে আমি কোথাকার নচ্ছার । আপনি যদি এটাকে পাস বাই রেফারেন্স হিসাবে অভিহিত করেন তবে সেটা আপনার ব্যাপার আর যদি পাস বাই ভ্যালু হিসাবে অভিহিত করেন তবে সেখানেও আমার কোন আপত্তি থাকার কথা নয় ।

যে কারনে এই আর্টিকেল লেখা সেটা হল আপনারা খারাপ ধাচের হলেও যেন কিছু জাভার প্রোগ্রাম পড়েন । অন্তত সেটুকু নিজে প্রাকটিস করেন । এটা পড়ে আহামরি কোন প্রোগ্রামার হয়ে যাবেন না সেটা আমি মনে প্রানে বিশ্বাস করি ।

সবশেষে একটা প্রশ্ন, কাহলিল জিবরান সাহেবের গল্পের কথা মনে আছেতো ? পানি কি আপনারা খেয়েছেন নাকি আমি খেয়েছি ? আমি খেলে সমস্যা নাই , আপনারা খেলে আমাকেও খানিকটা দিবেন, খেয়ে আপনাদের কাতারে ভিড়ে যাব ।

সবাইকে ধন্যবাদ ।

5 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. class ReferredObject {

    }

    public class ReferenceTest {

    public static void main(String[] args) {

    ReferredObject ro_1 = new ReferredObject();
    ReferredObject ro_2 = new ReferredObject();

    changeReference(ro_1, ro_2);
    }

    static void changeReference(
    ReferredObject ro_1, ReferredObject ro_2) {

    ro_1 = r0_2;
    }
    }



    If I print the references before calling the method changeReference() it shows two different references. In method I make two references identical. But after returning to caller it shows the references are different. Why does it happen?

    ReplyDelete
    Replies
    1. In 'changeReference' method when you are pointing 'ro_1' to 'ro_2' then 'ro_1' is being decoupled from it's previous reference and pointing to the reference point of 'ro_2'. Here you are just loosing 'ro_1' previous reference point and creating same reference point for 'ro_1' and 'ro_2' which is previously pointed by 'ro_2'.

      Delete
    2. I understood. Another question. I pass ro_1 and ro_2 references to changeReference(). There ro_1 = ro_2; results in decoupling current ro_1 from previous ro_1. is there any way to do the previous ro_1 points to ro_2 in changeReference() method just by passing references like now?

      Delete
    3. Technically yes in 'changeReference' method and no in 'main' method.

      You can refer any valid memory reference you want in changeReference method but you can't change those 'ro_1' and 'ro_2' pointed in 'main' method.
      Just check this out:
      class ReferredObject {

      }

      public class ReferenceTest {

      private static void changeReference(ReferredObject ro1, ReferredObject ro2){

      System.out.println("Before changing In changeReference");
      System.out.println(ro1.hashCode());
      System.out.println(ro2.hashCode());
      ReferredObject temp = ro1;
      ro1 = ro2;
      ro2 = temp;
      System.out.println("After changing In changeReference");
      System.out.println(ro1.hashCode());
      System.out.println(ro2.hashCode());
      }

      public static void main(String[] args) {

      ReferredObject r1 = new ReferredObject();
      ReferredObject r2 = new ReferredObject();
      System.out.println("Before Changing in main method");
      System.out.println(r1.hashCode());
      System.out.println(r2.hashCode());
      changeReference(r1, r2);
      System.out.println("After Changing in main method");
      System.out.println(r1.hashCode());
      System.out.println(r2.hashCode());
      }
      }

      Delete