কেন এনামের কনস্ট্রাক্টর স্থির ক্ষেত্রগুলিতে অ্যাক্সেস করতে পারে না?


110

কেন এনামের কনস্ট্রাক্টর স্থির ক্ষেত্র এবং পদ্ধতি অ্যাক্সেস করতে পারে না? এটি একটি শ্রেণীর সাথে পুরোপুরি বৈধ, তবে এনামের সাথে অনুমোদিত নয়।

আমি যা করার চেষ্টা করছি তা হল আমার এনাম উদাহরণগুলি স্থির মানচিত্রে সংরক্ষণ করা। এই উদাহরণ কোডটি বিবেচনা করুন যা সংক্ষিপ্তসার দ্বারা অনুসন্ধানের অনুমতি দেয়:

public enum Day {
    Sunday("Sun"), Monday("Mon"), Tuesday("Tue"), Wednesday("Wed"), Thursday("Thu"), Friday("Fri"), Saturday("Sat");

    private final String abbreviation;

    private static final Map<String, Day> ABBREV_MAP = new HashMap<String, Day>();

    private Day(String abbreviation) {
        this.abbreviation = abbreviation;
        ABBREV_MAP.put(abbreviation, this);  // Not valid
    }

    public String getAbbreviation() {
        return abbreviation;
    }

    public static Day getByAbbreviation(String abbreviation) {
        return ABBREV_MAP.get(abbreviation);
    }
}

এটি কাজ করবে না যেহেতু এনাম এটির নির্মাণকারীকে স্থির রেফারেন্সের অনুমতি দেয় না। এটি শ্রেণিবদ্ধ হিসাবে প্রয়োগ করা হয়েছে কিনা তা সন্ধান করতে কেবল কাজ করে:

public static final Day SUNDAY = new Day("Sunday", "Sun");
private Day(String name, String abbreviation) {
    this.name = name;
    this.abbreviation = abbreviation;
    ABBREV_MAP.put(abbreviation, this);  // Valid
}

উত্তর:


113

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

হ্যাঁ, এটি কিছুটা ব্যথা এবং সম্ভবত এটি আরও ভালভাবে ডিজাইন করা যেতে পারে।

তবে, আমার অভিজ্ঞতার সাধারণ উত্তরটি হ'ল static {}সমস্ত স্ট্যাটিক ইনিশিয়ালাইজারের শেষে একটি ব্লক থাকা উচিত এবং EnumSet.allOf সমস্ত মান অর্জনের জন্য সেখানে সমস্ত স্থির সূচনাকরণ করা উচিত ।


40
যদি আপনি কোনও নেস্টেড ক্লাস যুক্ত করেন, তবে এর স্ট্যাটিকগুলি একটি উপযুক্ত সময়ে শুরু করা হবে।
টম হাটিন -

ওহ, সুন্দর। আমি এটা ভাবিনি।
জন স্কিটি

3
একটি বিজোড়ের বিট তবে আপনি যদি এনাম কনস্ট্রাক্টরে কোনও স্ট্যাটিক পদ্ধতিতে কল করেন যা কোনও স্থিতিশীল মান দেয় এটি জরিমানা সংকলন করে - তবে মানটি যে মানটি দেয় তা সেই ধরণের জন্য পূর্বনির্ধারিত হবে (উদাহরণস্বরূপ, 0, 0.0, '00 u0000' বা নাল), এমনকি যদি আপনি এটিকে স্পষ্টভাবে সেট করে থাকেন (যতক্ষণ না এটি হিসাবে ঘোষণা করা হয় final)। অনুমান করুন যে এটি ধরা কঠিন হবে!
মার্ক রোডস

2
দ্রুত স্পিন-অফ প্রশ্ন @ জনস্কিট: আপনি যে কারণে ব্যবহার করছেন EnumSet.allOfতার বদলে Enum.values()? আমি জিজ্ঞাসা করি কারণ valuesএক ধরনের ভৌতিক পদ্ধতি (উত্সটি দেখতে পাচ্ছে না Enum.class) এবং কখন তৈরি হয় তা আমি জানি না
চিরলো

1
@ চিরলো এই সম্পর্কে একটি প্রশ্ন আছে । Enum.values()আপনি লুপের জন্য বর্ধিত (যেহেতু এটি একটি অ্যারের ফিরিয়ে দেয়) নিয়ে তাদের উপর পুনরাবৃত্তি করার পরিকল্পনা করেন তবে এটি বেশ দ্রুত, তবে বেশিরভাগই এটি স্টাইল এবং ব্যবহারের ক্ষেত্রে। EnumSet.allOf()জাভা ডকুমেন্টেশনে কেবলমাত্র চশমার পরিবর্তে বিদ্যমান কোডটি লিখতে চাইলে সম্ভবত এটি ব্যবহার করা আরও ভাল তবে অনেক লোক Enum.values()যেভাবেই তার সাথে পরিচিত বলে মনে হয় ।
ক্যাসেল

31

জেএলএস এর উদ্ধৃতি , বিভাগ "এনুম বডি ডিক্লারেশনস" :

এই নিয়ম ব্যতীত এনাম ধরণের সূচনা বিজ্ঞপ্তির কারণে আপাতদৃষ্টিতে যুক্তিসঙ্গত কোড চলমান সময়ে ব্যর্থ হবে would ("স্ব-টাইপযুক্ত" স্থির ক্ষেত্র সহ যে কোনও শ্রেণিতে একটি বিজ্ঞপ্তি বিদ্যমান)) এখানে কোডটি বাছাইয়ের একটি উদাহরণ যা ব্যর্থ হবে:

enum Color {
    RED, GREEN, BLUE;
    static final Map<String,Color> colorMap = new HashMap<String,Color>();

    Color() {
       colorMap.put(toString(), this);
    }
}

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

মনে রাখবেন যে উদাহরণটি সহজেই সঠিকভাবে কাজ করতে পারে:

enum Color {
    RED, GREEN, BLUE;
    static final Map<String,Color> colorMap = new HashMap<String,Color>();

    static {
        for (Color c : Color.values())
            colorMap.put(c.toString(), c);
    }
}

রিফ্যাক্টরড সংস্করণটি স্পষ্টভাবে সঠিক, কারণ স্থির সূচনাটি শীর্ষ থেকে নীচে ঘটে।


9

সম্ভবত এটি আপনি চান

public enum Day {
    Sunday("Sun"), 
    Monday("Mon"), 
    Tuesday("Tue"), 
    Wednesday("Wed"), 
    Thursday("Thu"), 
    Friday("Fri"), 
    Saturday("Sat");

    private static final Map<String, Day> ELEMENTS;

    static {
        Map<String, Day> elements = new HashMap<String, Day>();
        for (Day value : values()) {
            elements.put(value.element(), value);
        }
        ELEMENTS = Collections.unmodifiableMap(elements);
    }

    private final String abbr;

    Day(String abbr) {
        this.abbr = abbr;
    }

    public String element() {
        return this.abbr;
    }

    public static Day elementOf(String abbr) {
        return ELEMENTS.get(abbr);
    }
}

ব্যবহার Collections.unmodifiableMap()এখানে একটি খুব ভাল অনুশীলন। +1
ক্যাসেল

ঠিক আমি খুঁজছেন ছিল কি. আমি সংগ্রহগুলি.অনোমডিফাইয়েবল ম্যাপটি দেখতেও পছন্দ করি। ধন্যবাদ!
লেথাললিমা

6

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

enum Day {

    private static final class Helper {
        static Map<String,Day> ABBR_TO_ENUM = new HashMap<>();
    }

    Day(String abbr) {
        this.abbr = abbr;
        Helper.ABBR_TO_ENUM.put(abbr, this);

    }

    public static Day getByAbbreviation(String abbr) {
        return Helper.ABBR_TO_ENUM.get(abbr);
    }

1

যখন কোনও ক্লাসটি JVM এ লোড করা হয় তখন স্থিতিশীল ক্ষেত্রগুলি কোডে প্রদর্শিত হয় সেই ক্রমে সেগুলি শুরু করা হয়। যেমন যেমন

public class Test4 {
        private static final Test4 test4 = new Test4();
        private static int j = 6;
        Test4() {
            System.out.println(j);
        }
        private static void test() {
        }
        public static void main(String[] args) {
            Test4.test();
        }
    }

আউটপুটটি 0 হবে Note দ্রষ্টব্য যে টেস্ট 4 সূচনাটি স্থির সূচনা প্রক্রিয়াতে সঞ্চালিত হয় এবং এই সময়ের মধ্যে জে এখনও আরম্ভ হয় নি কারণ এটি পরে দেখা যায়। এখন আমরা যদি স্ট্যাটিক ইনিশিয়ালাইজারের ক্রমটি স্যুইচ করি যে জে টেস্ট 4 এর আগে আসে। আউটপুটটি 6. হবে তবে এনামসের ক্ষেত্রে আমরা স্থির ক্ষেত্রগুলির ক্রম পরিবর্তন করতে পারি না। এনামের প্রথম জিনিসটি অবশ্যই সেই ধ্রুবক হতে হবে যা প্রকৃতপক্ষে এনাম টাইপের স্থির চূড়ান্ত দৃষ্টান্ত। এটি এনাম কনস্ট্রাক্টরে তাদের অ্যাক্সেস করা অর্থহীন হবে।

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