একটি ভিন্ন পদ্ধতিতে সংজ্ঞায়িত অভ্যন্তর শ্রেণীর অভ্যন্তরে একটি চূড়ান্ত-চূড়ান্ত পরিবর্তন করতে পারে না


247

সম্পাদিত: টাইমার থেকে কয়েকবার চলার সাথে সাথে আমার বেশ কয়েকটি ভেরিয়েবলের মান পরিবর্তন করতে হবে। টাইমার দিয়ে আমার প্রতিটি পুনরাবৃত্তির সাথে মানগুলি আপডেট করে রাখা দরকার। আমি মানগুলিকে চূড়ান্ত হিসাবে সেট করতে পারি না কারণ এটি আমাকে মানগুলি আপডেট করা থেকে বিরত রাখবে তবে নীচের প্রাথমিক প্রশ্নে আমি বর্ণিত ত্রুটিটি পাচ্ছি:

আমি আগে যা নীচে লিখেছিলাম:

আমি ত্রুটিটি পাচ্ছি "আলাদা পদ্ধতিতে সংজ্ঞায়িত কোনও অভ্যন্তরীণ শ্রেণীর অভ্যন্তরে একটি চূড়ান্ত-চূড়ান্ত পরিবর্তন করতে পারে না"।

এটি ডাবল বলা দাম এবং দাম নামক দামের জন্য ঘটছে। আমি জানি কেন আমার এই সমস্যা হচ্ছে। আমার চূড়ান্ত ঘোষণা কেন দরকার তা আমি বুঝতে পারি না। এছাড়াও আপনি যদি দেখতে পান যে আমি এটি করার চেষ্টা করছি তবে এই সমস্যাটি পেতে আমাকে কী করতে হবে।

public static void main(String args[]) {

    int period = 2000;
    int delay = 2000;

    double lastPrice = 0;
    Price priceObject = new Price();
    double price = 0;

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            price = priceObject.getNextPrice(lastPrice);
            System.out.println();
            lastPrice = price;
        }
    }, delay, period);
}

আমি যা জিজ্ঞাসা করছি তা হ'ল আমি এমন টাইমারটিতে কীভাবে একটি পরিবর্তনশীল পাই যা আমি ধারাবাহিকভাবে আপডেট করতে পারি।
অঙ্কুর

1
@ অঙ্কুর: সহজ উত্তরটি "না"। তবে আপনি একটি অভ্যন্তর শ্রেণীর ব্যবহার করে পছন্দসই প্রভাব অর্জন করতে পারেন; @ পিটারকার্ডোনার উত্তর দেখুন।
স্টিফেন সি

উত্তর:


197

আপনার মতো বেনাম শ্রেণি ব্যবহার করার পরেও জাভা সত্যিকারের বন্ধকে সমর্থন করে না ( new TimerTask() { ... }) এখানে এক ধরণের বন্ধের মতো দেখাচ্ছে।

সম্পাদনা করুন - নীচের মন্তব্যগুলি দেখুন - কিপারঅফ দ্যসোলটি উল্লেখ করেছেন নিচের মত সঠিক ব্যাখ্যা নয়।

এ কারণেই এটি কার্যকর হয় না:

lastPriceমূল () পদ্ধতিতে ভেরিয়েবল এবং দাম স্থানীয় ভেরিয়েবল। আপনি বেনাম শ্রেণীর সাথে যে বস্তুটি তৈরি করেছেন তা main()পদ্ধতিটি ফিরে আসার আগে অবধি স্থায়ী হতে পারে ।

যখন main()পদ্ধতিটি ফিরে আসবে , স্থানীয় ভেরিয়েবলগুলি (যেমন lastPriceএবং price) স্ট্যাক থেকে পরিষ্কার হয়ে যাবে, সুতরাং main()রিটার্নের পরে সেগুলির আর অস্তিত্ব থাকবে না ।

কিন্তু বেনাম শ্রেণীর অবজেক্ট এই ভেরিয়েবলগুলি উল্লেখ করে। বেনাম শ্রেণীর অবজেক্টগুলি ভেরিয়েবলগুলি পরিষ্কার করার পরে অ্যাক্সেস করার চেষ্টা করলে জিনিসগুলি মারাত্মক ভুল হবে would

তৈরি করে lastPriceএবং price final, তারা আসলে আর পরিবর্তনশীল নয়, তবে ধ্রুবক। সংকলকটি তখন কেবল অজ্ঞাতনামা শ্রেণীর ব্যবহারগুলি lastPriceএবং priceধ্রুবকের মানগুলির সাথে প্রতিস্থাপন করতে পারে (অবশ্যই সংকলন সময়ে, অবশ্যই), এবং আপনার আর অস্তিত্বহীন ভেরিয়েবল অ্যাক্সেস করতে সমস্যা হবে না।

অন্যান্য প্রোগ্রামিং ল্যাঙ্গুয়েজগুলি ক্লোজারগুলিকে সমর্থন করে এটি সেই ভেরিয়েবলগুলিকে বিশেষভাবে চিকিত্সা করে - পদ্ধতিটি শেষ হয়ে গেলে তারা ধ্বংস হয় না তা নিশ্চিত করে, যাতে বন্ধটি এখনও ভেরিয়েবলগুলিতে অ্যাক্সেস করতে পারে।

@ অঙ্কুর: আপনি এটি করতে পারেন:

public static void main(String args[]) {
    int period = 2000;
    int delay = 2000;

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        // Variables as member variables instead of local variables in main()
        private double lastPrice = 0;
        private Price priceObject = new Price();
        private double price = 0;

        public void run() {
            price = priceObject.getNextPrice(lastPrice);
            System.out.println();
            lastPrice = price;
        }
    }, delay, period);      
}

34
একেবারেই সত্য নয়, জাভা তাদের চলমান সময়ের মানগুলি ক্যাপচার করতে ভেরিয়েবলের জন্য ক্যাপচার জেনারেট করে, কেবল তারা একটি অদ্ভুত পার্শ্ব-প্রতিক্রিয়া এড়াতে চেয়েছিল যে এটি সম্ভব। নেট যেখানে আপনি প্রতিনিধিটির মধ্যে মানটি ক্যাপচার করেন সেখানে পরিবর্তন করুন বহিরাগত পদ্ধতিতে মান এবং এখন ডেলিগেটটি জাভা এড়াতে চাইলে এই আচরণের সি # উদাহরণের জন্য নতুন মান দেখুন, স্ট্যাকওভারফ্লো.com / প্রশ্নগুলি / 271440/ c- captured-variable-in- লুপ দেখুন ।
ক্রিস চিলভার্স

14
এটি কোনও "অদ্ভুত পার্শ্ব-প্রতিক্রিয়া" নয়, এটি লোকেদের স্বাভাবিক আচরণের প্রত্যাশা করে - এবং যা জাভা সরবরাহ করতে পারে না কারণ এটি ক্যাপচার তৈরি করে না। কার্যকারণ হিসাবে, বেনাম শ্রেণিতে ব্যবহৃত স্থানীয় ভেরিয়েবলগুলি অবশ্যই চূড়ান্ত হতে হবে।
মাইকেল বর্গওয়ার্ট

12
জেস্পার, আপনার উত্তরগুলির ভুল অংশগুলি সম্ভবত সম্পাদনা করা উচিত তবে কেবল উপরেরটি ভুল বলে ম্যাসেজ দেওয়া উচিত।
জেমস ম্যাকমাহন

19
জাভা বাস্তবে ক্লোজার সমর্থন করে না। ক্লোজারগুলিকে সমর্থন করে এমন ভাষাগুলি হ্যাপ অবজেক্ট হিসাবে পুরো স্থানীয় পরিবেশ (এটি বর্তমান স্ট্যাক ফ্রেমে সংজ্ঞায়িত স্থানীয় ভেরিয়েবলগুলির সেট) সংরক্ষণ করে করে। জাভা এর পক্ষে সমর্থন করে না (ভাষা ডিজাইনাররা এটি বাস্তবায়ন করতে চেয়েছিল তবে সময়ের বাইরে চলে গিয়েছিল), সুতরাং যখন কোনও স্থানীয় শ্রেণি তাত্ক্ষণিকভাবে প্রয়োগ করা হয় তখন যে কোনও স্থানীয় ভেরিয়েবলের মানগুলি যেটিকে বোঝায় তা স্তূপে অনুলিপি করা হয় । যাইহোক, জেভিএম তার পরে স্থানীয় ভেরিয়েবলগুলির সাথে মানগুলিকে সমন্বয় করতে পারে না, এ কারণেই তাদের চূড়ান্ত হতে হবে।
টায়মন

64
এই উত্তরটি এখন পুরোপুরি বিভ্রান্ত হচ্ছে যে "কিপারআফ দ্যসসুল" নামে কেউ নেই যারা এতে মন্তব্য করেছে। উত্তরটি সংশোধন করা উচিত।
অ্যাডাম পার্কিন

32

অনামী প্রতিনিধি দ্বারা রেফারেন্স করা জাভা ভেরিয়েবলগুলিতে ক্লোজারগুলির সাথে অদ্ভুত পার্শ্ব প্রতিক্রিয়া এড়াতে চূড়ান্ত হিসাবে চিহ্নিত করতে হবে, তাই lastPriceটাইমার টাস্কের মধ্যে উল্লেখ এবং মূল্যকে চূড়ান্ত হিসাবে চিহ্নিত করা দরকার।

এটি অবশ্যই আপনার পক্ষে কাজ করবে না কারণ আপনি এগুলি পরিবর্তন করতে চান, এই ক্ষেত্রে আপনাকে তাদের ক্লাসের মধ্যে সজ্জিত করা উচিত।

public class Foo {
    private PriceObject priceObject;
    private double lastPrice;
    private double price;

    public Foo(PriceObject priceObject) {
        this.priceObject = priceObject;
    }

    public void tick() {
        price = priceObject.getNextPrice(lastPrice);
        lastPrice = price;
    }
}

এখনই চূড়ান্ত হিসাবে একটি নতুন ফু তৈরি করুন এবং টাইমার থেকে .টিক কল করুন।

public static void main(String args[]){
    int period = 2000;
    int delay = 2000;

    Price priceObject = new Price();
    final Foo foo = new Foo(priceObject);

    Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            foo.tick();
        }
    }, delay, period);
}

1
অথবা আপনি কেবল ফুুনকে রান্নেবল বাস্তবায়িত করতে পারেন ..?
বিদ্বেষ

18

বেনামে বর্গ ব্যবহার করার সময় আপনি কেবলমাত্র অন্তর্ভুক্ত শ্রেণীর থেকে চূড়ান্ত পরিবর্তনশীল অ্যাক্সেস করতে পারেন। অতএব আপনাকে ভেরিয়েবলগুলি চূড়ান্ত হিসাবে ব্যবহৃত হচ্ছে তা ঘোষণা করতে হবে (যেহেতু আপনি সর্বশেষ মূল্য এবং দাম পরিবর্তন করছেন তাই এটি আপনার পক্ষে নয়) ), বা শ্রেণি ব্যবহার করবেন না।

সুতরাং আপনার বিকল্পগুলি হ'ল একটি আসল অভ্যন্তর শ্রেণি তৈরি করা, যাতে আপনি ভেরিয়েবলগুলিতে পাস করতে পারেন এবং এগুলিকে একটি সাধারণ ফ্যাশনে ব্যবহার করতে পারেন

বা:

আপনার লাস্টপ্রাইস এবং দাম ভেরিয়েবলের জন্য একটি দ্রুত (এবং আমার মতে কুৎসিত) হ্যাক রয়েছে যা এটির মতো ঘোষণা করে to

final double lastPrice[1];
final double price[1];

এবং আপনার বেনামে শ্রেণিতে আপনি এই জাতীয় মান সেট করতে পারেন

price[0] = priceObject.getNextPrice(lastPrice[0]);
System.out.println();
lastPrice[0] = price[0];

14

আপনি ইতিমধ্যে সরবরাহিত যা করার চেষ্টা করছেন তা আপনি কেন করতে পারবেন না তার জন্য ভাল ব্যাখ্যা। সমাধান হিসাবে, বিবেচনা করুন:

public class foo
{
    static class priceInfo
    {
        public double lastPrice = 0;
        public double price = 0;
        public Price priceObject = new Price ();
    }

    public static void main ( String args[] )
    {

        int period = 2000;
        int delay = 2000;

        final priceInfo pi = new priceInfo ();
        Timer timer = new Timer ();

        timer.scheduleAtFixedRate ( new TimerTask ()
        {
            public void run ()
            {
                pi.price = pi.priceObject.getNextPrice ( pi.lastPrice );
                System.out.println ();
                pi.lastPrice = pi.price;

            }
        }, delay, period );
    }
}

মনে হয় সম্ভবত আপনি এর চেয়ে আরও ভাল একটি নকশা করতে পারেন, তবে ধারণাটি হ'ল আপনি পরিবর্তিত নয় এমন শ্রেণীর রেফারেন্সের মধ্যে আপডেট হওয়া ভেরিয়েবলগুলি গ্রুপ করতে পারেন।


11

বেনাম ক্লাস সহ, আপনি আসলে একটি "নামহীন" নেস্টেড ক্লাস ঘোষণা করছেন। নেস্টেড ক্লাসগুলির জন্য, সংকলকটি কনস্ট্রাক্টরের সাথে একটি নতুন স্ট্যান্ডেলোন পাবলিক ক্লাস তৈরি করে যা এটি আর্গুমেন্ট হিসাবে ব্যবহার করে এমন সমস্ত ভেরিয়েবল গ্রহণ করবে ("নামযুক্ত" নেস্টেড ক্লাসগুলির জন্য, এটি সর্বদা আসল / ঘেরযুক্ত শ্রেণীর উদাহরণ)। এটি করা হয়েছে কারণ রানটাইম পরিবেশে নেস্টেড ক্লাসগুলির কোনও ধারণা নেই, তাই নেস্টেড থেকে স্ট্যান্ডেলোন ক্লাসে একটি (স্বয়ংক্রিয়) রূপান্তর হওয়া দরকার।

উদাহরণস্বরূপ এই কোডটি নিন:

public class EnclosingClass {
    public void someMethod() {
        String shared = "hello"; 
        new Thread() {
            public void run() {
                // this is not valid, won't compile
                System.out.println(shared); // this instance expects shared to point to the reference where the String object "hello" lives in heap
            }
        }.start();

        // change the reference 'shared' points to, with a new value
        shared = "other hello"; 
        System.out.println(shared);
    }
}

এটি কাজ করবে না, কারণ সংকলক হুডের নীচে এটি করে:

public void someMethod() {
    String shared = "hello"; 
    new EnclosingClass$1(shared).start();

    // change the reference 'shared' points to, with a new value
    shared = "other hello"; 
    System.out.println(shared);
}

মূল বেনাম শ্রেণীর সংকলকটি উত্পন্ন কয়েকটি স্ট্যান্ডেলোন শ্রেণীর দ্বারা প্রতিস্থাপিত হয় (কোডটি সঠিক নয়, তবে আপনাকে একটি ভাল ধারণা দেওয়া উচিত):

public class EnclosingClass$1 extends Thread {
    String shared;
    public EnclosingClass$1(String shared) {
        this.shared = shared;
    }

    public void run() {
        System.out.println(shared);
    }
}

যেমন আপনি দেখতে পাচ্ছেন, স্ট্যান্ডেলোন ক্লাসটি ভাগ করা বস্তুর রেফারেন্স রাখে, মনে রাখবেন জাভাতে সমস্ত কিছুই পাস-বাই-ভ্যালু, সুতরাং এনক্লোসিংক্লাসে রেফারেন্স ভেরিয়েবল 'ভাগ করা' পরিবর্তিত হয়ে গেলেও, যে উদাহরণটি এটি নির্দেশ করে তা সংশোধন করা হয়নি , এবং এটিতে নির্দেশিত অন্যান্য সমস্ত রেফারেন্স ভেরিয়েবলগুলি (বেনামে শ্রেণীর মতো: $ 1 সংযুক্ত করে), এটি সম্পর্কে সচেতন হবে না। এটিই মূল কারণ যা সংকলক আপনাকে এই 'ভাগ করা' ভেরিয়েবলগুলি চূড়ান্ত হিসাবে ঘোষণা করতে বাধ্য করে, যাতে এই ধরণের আচরণ এটি ইতিমধ্যে আপনার চলমান কোডে পরিণত না করে।

এখন, আপনি যখন বেনাম শ্রেণীর অভ্যন্তরে কোনও উদাহরণ পরিবর্তনশীল ব্যবহার করেন তখন এটি ঘটে থাকে (আপনার সমস্যা সমাধানের জন্য আপনার এই কাজটি করা উচিত, আপনার যুক্তিটিকে একটি "উদাহরণ" পদ্ধতিতে বা কোনও শ্রেণীর নির্মাতায় সরিয়ে দিন):

public class EnclosingClass {
    String shared = "hello";
    public void someMethod() {
        new Thread() {
            public void run() {
                System.out.println(shared); // this is perfectly valid
            }
        }.start();

        // change the reference 'shared' points to, with a new value
        shared = "other hello"; 
        System.out.println(shared);
    }
}

এটি সূক্ষ্ম সংকলন করে, কারণ সংকলক কোডটি সংশোধন করবে, যাতে নতুন উত্পন্ন শ্রেণি এনকোলেসিং $ 1 যেখানে এটি ইনস্ট্যান্ট করা হয়েছিল সেখানে এনক্লোসিংক্লাসের উদাহরণটির একটি রেফারেন্স রাখবে (এটি কেবল একটি উপস্থাপনা, তবে আপনাকে যেতে দেওয়া উচিত):

public void someMethod() {
    new EnclosingClass$1(this).start();

    // change the reference 'shared' points to, with a new value
    shared = "other hello"; 
    System.out.println(shared);
}

public class EnclosingClass$1 extends Thread {
    EnclosingClass enclosing;
    public EnclosingClass$1(EnclosingClass enclosing) {
        this.enclosing = enclosing;
    }

    public void run() {
        System.out.println(enclosing.shared);
    }
}

এটির মতো, যখন এনক্লোসিংক্লাসের রেফারেন্স ভেরিয়েবলটি 'ভাগ করা' পুনরায় স্বাক্ষরিত হয় এবং থ্রেড # রান () এর কল করার আগে এটি ঘটে, আপনি "অন্যান্য হ্যালো" দু'বার মুদ্রিত দেখতে পাবেন, কারণ এখন এনক্লোসিংক্লাস # 1 # এনকোলেসিং ভেরিয়েবল একটি রেফারেন্স রাখবে যে শ্রেণীর এটি ঘোষিত হয়েছিল তার অবজেক্টে, সুতরাং সেই বস্তুর যে কোনও বৈশিষ্ট্যে পরিবর্তনগুলি এনক্লোজিংক্লাস $ 1 এর উদাহরণগুলিতে দৃশ্যমান হবে।

বিষয় সম্পর্কে আরও তথ্যের জন্য, আপনি এই দুর্দান্ত ব্লগ পোস্টটি দেখতে পাবেন (আমার দ্বারা লিখিত নয়): http://kevinboone.net/java_inner.html


লোকাল ভেরিয়েবল 'শেয়ারড' যদি কোনও মিউটেটেবল অবজেক্ট হয় তবে কী হবে? আপনার ব্যাখ্যা অনুসারে 'চূড়ান্ত' ঘোষণা করা কোনওভাবেই সহায়তা করবে না, তাই না?
sactiw

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

>>> তবে এর মান পরিবর্তন হবে না আমি অনুমান করি আপনি বিন্দুটি অনুপস্থিত রয়েছেন অর্থাত্ যদি চূড়ান্ত রেফারেন্স ভেরিয়েবলটি কোনও পরিবর্তনীয় বস্তুর দিকে ইঙ্গিত করে তবে এটি আপডেট করা যায় তবে বেনাম বর্গ অগভীর অনুলিপি তৈরি করে বেনামে পরিবর্তনগুলি প্রতিফলিত হয় বর্গ। অন্য কথায়, রাজ্য সিঙ্কে রয়েছে যা এখানে পছন্দসই। এখানে, ওপি অংশীদারি ভেরিয়েবল (প্রিমিটিভ টাইপ) সংশোধন করার জন্য দক্ষতা প্রয়োজন এবং এটি অর্জনের জন্য ওপিকে একটি পরিবর্তনীয় অবজেক্টের অধীনে মানটি আবৃত করতে হবে এবং সেই পরিবর্তনীয় বস্তুটি ভাগ করতে হবে।
sactiw

1
অবশ্যই ওপি প্রয়োজনীয় মানটিকে একটি পরিবর্তনীয় অবজেক্টের আওতায় আনতে পারে, ভেরিয়েবলটিকে চূড়ান্ত হিসাবে ঘোষণা করতে পারে এবং পরিবর্তে এটি ব্যবহার করতে পারে। তবে তিনি চলক শ্রেণীর একটি গুণ হিসাবে (উত্তরে নির্দেশিত ও বর্ণিত হিসাবে) ভেরিয়েবলটিকে ঘোষিত করে একটি অতিরিক্ত বস্তু ব্যবহার এড়াতে পারবেন। পরিবর্তনীয় অবজেক্টগুলিকে বাধ্য করা (যেমন ভাগ করা ভেরিয়েবলের মান পরিবর্তন করতে সক্ষম হবার জন্য অ্যারে ব্যবহার করা) কোনও ভাল ধারণা নয়।
এমেরিনো

7

আমি যখন এই সমস্যাটিতে হোঁচট খাই তখন আমি কেবল কনস্ট্রাক্টরের মাধ্যমে অবজেক্টগুলি অভ্যন্তরীণ শ্রেণিতে পাস করি। আমার যদি আদিম বা অপরিবর্তনীয় বস্তুগুলি (যেমন এই ক্ষেত্রে) পাস করার প্রয়োজন হয় তবে একটি র‌্যাপার ক্লাস প্রয়োজন।

সম্পাদনা করুন: আসলে আমি কোনও বেনাম শ্রেণি ব্যবহার করি না, তবে একটি উপযুক্ত সাবক্লাস:

public class PriceData {
        private double lastPrice = 0;
        private double price = 0;

        public void setlastPrice(double lastPrice) {
            this.lastPrice = lastPrice;
        }

        public double getLastPrice() {
            return lastPrice;
        }

        public void setPrice(double price) {
            this.price = price;
        }

        public double getPrice() {
            return price;
        }
    }

    public class PriceTimerTask extends TimerTask {
        private PriceData priceData;
        private Price priceObject;

        public PriceTimerTask(PriceData priceData, Price priceObject) {
            this.priceData = priceData;
            this.priceObject = priceObject;
        }

        public void run() {
            priceData.setPrice(priceObject.getNextPrice(lastPrice));
            System.out.println();
            priceData.setLastPrice(priceData.getPrice());

        }
    }

    public static void main(String args[]) {

        int period = 2000;
        int delay = 2000;

        PriceData priceData = new PriceData();
        Price priceObject = new Price();

        Timer timer = new Timer();

        timer.scheduleAtFixedRate(new PriceTimerTask(priceData, priceObject), delay, period);
    }

2

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


2

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

তবে, আপনি যদি জেনেরিক ইন্টারফেস ক্লাস লিখছেন তবে আপনাকে একটি অবজেক্ট পাস করতে হবে, অথবা অবজেক্টের আরও ভাল একটি তালিকা দিতে হবে। এটি অবজেক্ট [] বা আরও ভাল, বস্তু দ্বারা করা যেতে পারে ... কারণ কল করা আরও সহজ।

ঠিক নীচে আমার উদাহরণ টুকরা দেখুন।

List<String> lst = new ArrayList<String>();
lst.add("1");
lst.add("2");        

SomeAbstractClass p = new SomeAbstractClass (lst, "another parameter", 20, true) {            

    public void perform( ) {                           
        ArrayList<String> lst = (ArrayList<String>)getArgs()[0];                        
    }

};

public abstract class SomeAbstractClass{    
    private Object[] args;

    public SomeAbstractClass(Object ... args) {
        this.args = args;           
    }      

    public abstract void perform();        

    public Object[] getArgs() {
        return args;
    }

}

দয়া করে জাভা বন্ধ সম্পর্কে এই পোস্টটি দেখুন যা এটি বক্সের বাইরে সমর্থন করে: http://mseifed.blogspot.se/2012/09/closure-implementation-for-java-5-6-and.html

সংস্করণ 1 অটোকাস্টিং সহ চূড়ান্ত অবসান ঘটাতে সমর্থন করে:
https://github.com/MSeifeddo/Closure-implementation-for-Java-5-6-and-7/blob/master/org/mo/closure/v1/ Closure.java

    SortedSet<String> sortedNames = new TreeSet<String>();
    // NOTE! Instead of enforcing final, we pass it through the constructor
    eachLine(randomFile0, new V1<String>(sortedNames) {
        public void call(String line) {
            SortedSet<String> sortedNames = castFirst();  // Read contructor arg zero, and auto cast it
            sortedNames.add(extractName(line));
        }
    });

2

আপনি যদি কোনও বেনাম শ্রেণীর মধ্যে কোনও মেথড কলের মান পরিবর্তন করতে চান তবে সেই "মান" আসলে একটি Future। সুতরাং, আপনি যদি পেয়ারা ব্যবহার করেন, আপনি লিখতে পারেন

...
final SettableFuture<Integer> myvalue = SettableFuture<Integer>.create();
...
someclass.run(new Runnable(){

    public void run(){
        ...
        myvalue.set(value);
        ...
    }
 }

 return myvalue.get();

2

একটি সমাধান আমি লক্ষ্য করেছি যে উল্লেখ করা হয়নি (যতক্ষণ না আমি এটি মিস করেছি, যদি আমি দয়া করে আমাকে সংশোধন না করি), এটি একটি বর্গ ভেরিয়েবলের ব্যবহার। কোনও পদ্ধতির মধ্যে একটি নতুন থ্রেড চালানোর চেষ্টা করে এই সমস্যাটি ছড়িয়ে পড়ে:new Thread(){ Do Something }

doSomething()নিম্নলিখিত থেকে কল করা কাজ করবে। আপনার অগত্যা এটি ঘোষণা করার finalদরকার নেই, কেবল ভেরিয়েবলের স্কোপ পরিবর্তন করা দরকার যাতে এটি আভ্যন্তর শ্রেণীর আগে সংগ্রহ করা হয় না। এটি অবশ্যই যদি না আপনার প্রক্রিয়া বিশাল হয় এবং সুযোগ পরিবর্তন পরিবর্তন এক ধরণের দ্বন্দ্ব তৈরি করতে পারে। আমি আমার পরিবর্তনশীলটিকে চূড়ান্ত করতে চাইনি কারণ এটি কোনওভাবেই চূড়ান্ত / ধ্রুবক নয়।

public class Test
{

    protected String var1;
    protected String var2;

    public void doSomething()
    {
        new Thread()
        {
            public void run()
            {
                System.out.println("In Thread variable 1: " + var1);
                System.out.println("In Thread variable 2: " + var2);
            }
        }.start();
    }

}

1

যদি ভেরিয়েবলটি চূড়ান্ত হওয়ার প্রয়োজন হয় তবে তা না হয়ে আপনি ভেরিয়েবলের মান অন্য ভেরিয়েবলের কাছে বরাদ্দ করতে পারেন এবং চূড়ান্ত করতে পারেন যাতে আপনি পরিবর্তে এটি ব্যবহার করতে পারেন।


1

চূড়ান্ত-অযোগ্য চলকটি উল্লেখ করতে ClassName.this.variableName ব্যবহার করুন


1

আপনি কেবল বহিরাগত শ্রেণীর বাইরে চলকটি ঘোষণা করতে পারেন। এর পরে, আপনি অভ্যন্তর শ্রেণীর মধ্যে থেকে পরিবর্তনশীল সম্পাদনা করতে সক্ষম হবেন। অ্যান্ড্রয়েডে কোডিং করার সময় আমি মাঝে মাঝে একইরকম সমস্যার মুখোমুখি হই তাই আমি পরিবর্তনশীলটিকে বিশ্বব্যাপী হিসাবে ঘোষণা করি এবং এটি আমার পক্ষে কাজ করে।


এটি সত্যিকার অর্থে প্রশ্নের উত্তর দেয় না ... এজন্য আপনি কেন নিচে নামাচ্ছেন।
স্টুয়ার্ট সিগেলার


0

মূল উদ্বেগটি বেনাম শ্রেণীর উদাহরণের মধ্যে কোনও পরিবর্তনশীল রান-টাইমে সমাধান করা যায় কিনা। চলকটি রান-টাইম স্কোপের অভ্যন্তরে থাকা অবস্থায় গ্যারান্টিযুক্ত হওয়া সত্ত্বেও ভেরিয়েবলকে চূড়ান্ত করতে হবে না। উদাহরণস্বরূপ, দয়া করে আপডেটস্ট্যাটাস () পদ্ধতির ভিতরে দুটি ভেরিয়েবল _statusMessage এবং _statusTextView দেখুন।

public class WorkerService extends Service {

Worker _worker;
ExecutorService _executorService;
ScheduledExecutorService _scheduledStopService;

TextView _statusTextView;


@Override
public void onCreate() {
    _worker = new Worker(this);
    _worker.monitorGpsInBackground();

    // To get a thread pool service containing merely one thread
    _executorService = Executors.newSingleThreadExecutor();

    // schedule something to run in the future
    _scheduledStopService = Executors.newSingleThreadScheduledExecutor();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    ServiceRunnable runnable = new ServiceRunnable(this, startId);
    _executorService.execute(runnable);

    // the return value tells what the OS should
    // do if this service is killed for resource reasons
    // 1. START_STICKY: the OS restarts the service when resources become
    // available by passing a null intent to onStartCommand
    // 2. START_REDELIVER_INTENT: the OS restarts the service when resources
    // become available by passing the last intent that was passed to the
    // service before it was killed to onStartCommand
    // 3. START_NOT_STICKY: just wait for next call to startService, no
    // auto-restart
    return Service.START_NOT_STICKY;
}

@Override
public void onDestroy() {
    _worker.stopGpsMonitoring();
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

class ServiceRunnable implements Runnable {

    WorkerService _theService;
    int _startId;
    String _statusMessage;

    public ServiceRunnable(WorkerService theService, int startId) {
        _theService = theService;
        _startId = startId;
    }

    @Override
    public void run() {

        _statusTextView = MyActivity.getActivityStatusView();

        // get most recently available location as a latitude /
        // longtitude
        Location location = _worker.getLocation();
        updateStatus("Starting");

        // convert lat/lng to a human-readable address
        String address = _worker.reverseGeocode(location);
        updateStatus("Reverse geocoding");

        // Write the location and address out to a file
        _worker.save(location, address, "ResponsiveUx.out");
        updateStatus("Done");

        DelayedStopRequest stopRequest = new DelayedStopRequest(_theService, _startId);

        // schedule a stopRequest after 10 seconds
        _theService._scheduledStopService.schedule(stopRequest, 10, TimeUnit.SECONDS);
    }

    void updateStatus(String message) {
        _statusMessage = message;

        if (_statusTextView != null) {
            _statusTextView.post(new Runnable() {

                @Override
                public void run() {
                    _statusTextView.setText(_statusMessage);

                }

            });
        }
    }

}

0

আমার জন্য যা কাজ করেছে তা কেবল আপনার এই ফাংশনের বাইরে ভেরিয়েবলকে সংজ্ঞায়িত করা হয়।

মূল ফাংশন যেমন ঘোষণা আগে ঠিক

Double price;
public static void main(String []args(){
--------
--------
}

এটি কাজ করবে না, আপনি উদাহরণটি পরিবর্তনশীল হিসাবে ঘোষণা করছেন, এটি ব্যবহার করার জন্য আপনাকে আপনার মূল পদ্ধতির অভ্যন্তরে একটি উদাহরণ তৈরি করতে হবে। আপনার হয় আরও সুনির্দিষ্ট হতে হবে বা কেবল 'দাম' ভেরিয়েবলের স্থিতিশীল সংশোধক যুক্ত করা উচিত।
এমেরিনো

0

পরিবর্তনশীলটিকে স্থির হিসাবে ঘোষণা করুন এবং প্রয়োজনীয় শ্রেণিতে ClassName.variable ব্যবহার করে উল্লেখ করুন


Non-static parameter cannot be referenced from a static context
স্টিফেন

@ শ্বেতা স্থানীয় ভেরিয়েবল এবং পদ্ধতির পরামিতিগুলি 'স্থিতিশীল' হিসাবে ঘোষণা করা যায় না, তদুপরি, পদ্ধতিটির পরেও স্থানীয় ভেরিয়েবল এবং পদ্ধতি পরামিতিগুলিতে অ্যাক্সেস চালিয়ে যাওয়ার পদ্ধতিটি (স্থানীয় বেনাম শ্রেণিগুলি) এটি যেভাবে প্রয়োগ করা হয়েছে তা প্রায় এটিই is ফিরে এসেছে অর্থাৎ এটি তাদের 'চূড়ান্ত' অনুলিপি তৈরি করে এবং সেগুলি উদাহরণ ভেরিয়েবল হিসাবে ব্যবহার করে।
স্যাটিউ

0

শুধু একটি অন্য ব্যাখ্যা। নীচে এই উদাহরণ বিবেচনা করুন

public class Outer{
     public static void main(String[] args){
         Outer o = new Outer();
         o.m1();        
         o=null;
     }
     public void m1(){
         //int x = 10;
         class Inner{
             Thread t = new Thread(new Runnable(){
                 public void run(){
                     for(int i=0;i<10;i++){
                         try{
                             Thread.sleep(2000);                            
                         }catch(InterruptedException e){
                             //handle InterruptedException e
                         }
                         System.out.println("Thread t running");                             
                     }
                 }
             });
         }
         new Inner().t.start();
         System.out.println("m1 Completes");
    }
}

এখানে আউটপুট হবে

এম 1 সম্পূর্ণ

থ্রেড টি চলছে

থ্রেড টি চলছে

থ্রেড টি চলছে

................

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

এটি সমাধান করার জন্য আমাদের স্থানীয় ভেরিয়েবলের একটি অনুলিপি তৈরি করতে হবে এবং তারপরে অন্দর শ্রেণীর অবজেক্টের সাথে হ্যাপে অনুলিপি করতে হবে, জাভা কেবল চূড়ান্ত ভেরিয়েবলের জন্য কি করে কারণ তারা আসলে পরিবর্তনশীল নয় কারণ তারা ধ্রুবকের মতো হয় (সবকিছু কেবল সংকলনের সময়ে ঘটে থাকে) রানটাইমে নয়)।


-1

উপরের সমস্যা সমাধানের জন্য, বিভিন্ন ভাষা বিভিন্ন সিদ্ধান্ত নেয়।

জাভা জন্য, সমাধান আমরা এই নিবন্ধে দেখুন হিসাবে হয়।

সি # এর জন্য, সমাধানটি পার্শ্ব-প্রতিক্রিয়াগুলির অনুমতি দেয় এবং রেফারেন্স দ্বারা ক্যাপচার করা একমাত্র বিকল্প।

সি ++ 11 এর জন্য, সমাধানটি হ'ল প্রোগ্রামারকে সিদ্ধান্ত নিতে দেওয়া। তারা মান বা রেফারেন্স দ্বারা ক্যাপচার চয়ন করতে পারেন। যদি মান অনুসারে ক্যাপচার করা হয় তবে কোনও পার্শ্ব-প্রতিক্রিয়া ঘটবে না কারণ ভেরিয়েবল রেফারেন্সটি আসলে ভিন্ন। যদি রেফারেন্স অনুসারে ক্যাপচার হয়, পার্শ্ব-প্রতিক্রিয়া দেখা দিতে পারে তবে প্রোগ্রামারটিকে এটি উপলব্ধি করা উচিত।


-2

কারণ ভেরিয়েবল চূড়ান্ত না হলে এটি বিভ্রান্তিকর, কারণ এতে পরিবর্তনগুলি বেনাম শ্রেণিতে নেওয়া হবে না।

কেবল ভেরিয়েবলগুলিকে 'দাম' এবং 'লাস্টপ্রিস' চূড়ান্ত করুন।

- সম্পাদনা করুন

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


2
এটি কেবল বিভ্রান্তিকর নয় - এটির সম্পূর্ণরূপে ভুল, সুতরাং সংকলক এটির অনুমতি দেয় না।
চিআই

তবে আমি যখন প্রয়োজন তখন মানগুলি কীভাবে পরিবর্তন করব?
অঙ্কুর

এটি বিভ্রান্তিকর কারণে নয়; এটি কারণ জাভা ক্লোজারগুলি সমর্থন করে না। আমার উত্তর নীচে দেখুন। @ অঙ্কুর: আপনি মূল () এর স্থানীয় ভেরিয়েবলের পরিবর্তে বেনামে বর্গ বস্তুর ভেরিয়েবল সদস্য ভেরিয়েবলগুলি তৈরি করতে পারেন।
জেস্পার

তিনি তাদের সংশোধন করছেন, সুতরাং তারা চূড়ান্ত হতে পারে না।
রবিন 13

যদি দাম এবং লাস্টপ্রাইস চূড়ান্ত হয়, তাদেরকে দেওয়া কার্যগুলি সংকলন করবে না।
গ্রেগ ম্যাটেস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.