জাভা এনুম সংজ্ঞা


151

আমি ভেবেছিলাম আমি জাভা জেনেরিকগুলি বেশ ভালভাবে বুঝতে পেরেছি, কিন্তু তারপরে আমি জাভা.এলং-এ নিম্নলিখিতগুলি পেয়েছি:

class Enum<E extends Enum<E>>

এই ধরণের পরামিতিটি কীভাবে ব্যাখ্যা করা যায় কেউ ব্যাখ্যা করতে পারেন? একই ধরণের পরামিতি ব্যবহার করা যেতে পারে যেখানে অন্যান্য উদাহরণ সরবরাহের জন্য বোনাস পয়েন্ট।


9
এখানে আমার ব্যাখ্যাটি সবচেয়ে বেশি পছন্দ হয়েছে: গ্রুমিং এনুম (ওরফে এনুম & lt; ই এনুমকে & lt; E >> প্রসারিত)
অ্যালান মুর

এই প্রশ্ন সবচেয়ে ভালো উত্তর আছে: stackoverflow.com/a/3068001/2413303
EpicPandaForce

উত্তর:


105

এর অর্থ হ'ল এনুমের জন্য টাইপ আর্গুমেন্টটি এমন এনম থেকে উদ্ভূত হয় যা নিজে একই ধরণের যুক্তিযুক্ত। কীভাবে এটি ঘটতে পারে? টাইপ আর্গুমেন্ট তৈরি করে নিজেই নতুন টাইপ করুন। সুতরাং যদি আমি স্ট্যাটাসকোড নামে একটি এনাম পেয়েছি তবে এটি সমান হবে:

public class StatusCode extends Enum<StatusCode>

এখন যদি আপনি সীমাবদ্ধতার পরীক্ষা, আমরা পেয়েছেন Enum<StatusCode>- তাই E=StatusCode। আসুন চেক করুন: Eপ্রসারিত হয় Enum<StatusCode>? হ্যাঁ! আমরা ঠিক আছি

আপনি নিজেরাই নিজেকে ভালভাবে জিজ্ঞাসা করতে পারেন এর মূল বিষয়টি কী: :) ওয়েল, এর অর্থ এনুমের এপিআই নিজেই উল্লেখ করতে পারে - উদাহরণস্বরূপ, এই Enum<E>প্রয়োগগুলি বলতে সক্ষম হয়ে Comparable<E>। বেস ক্লাসটি তুলনা করতে সক্ষম (এনামগুলির ক্ষেত্রে) তবে এটি নিশ্চিত করতে পারে যে এটি কেবল সঠিক ধরণের এনামগুলির একে অপরের সাথে তুলনা করে। (সম্পাদনা: আচ্ছা, প্রায় - নীচে সম্পাদনাটি দেখুন))

আমি আমার সি # পোর্ট প্রোটোকলবাফারগুলিতে অনুরূপ কিছু ব্যবহার করেছি। সেখানে "বার্তা" (অপরিবর্তনীয়) এবং "নির্মাতারা" (পরিবর্তনযোগ্য, একটি বার্তা তৈরি করতে ব্যবহৃত হয়) - এবং এগুলি জোড়া ধরণের হিসাবে আসে। জড়িত ইন্টারফেসগুলি হ'ল:

public interface IBuilder<TMessage, TBuilder>
  where TMessage : IMessage<TMessage, TBuilder> 
  where TBuilder : IBuilder<TMessage, TBuilder>

public interface IMessage<TMessage, TBuilder>
  where TMessage : IMessage<TMessage, TBuilder> 
  where TBuilder : IBuilder<TMessage, TBuilder>

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

সম্পাদনা: নোট করুন যে এটি আপনাকে বিজোড় প্রকার তৈরি করতে বাধা দেয় না যা কোনও টাইপ আর্গুমেন্ট ব্যবহার করে যা নিজেই ঠিক আছে, তবে যা একই ধরণের নয়। উদ্দেশ্যটি হ'ল ভুল ক্ষেত্রে থেকে আপনাকে রক্ষা করার চেয়ে সঠিক ক্ষেত্রে সুবিধা দেওয়া ।

সুতরাং Enumজাভাতে যদি "বিশেষভাবে" পরিচালনা না করা হয় তবে আপনি (মন্তব্যে উল্লিখিত হিসাবে) নিম্নলিখিত ধরণের তৈরি করতে পারেন:

public class First extends Enum<First> {}
public class Second extends Enum<First> {}

SecondComparable<First>পরিবর্তে বাস্তবায়ন Comparable<Second>... কিন্তু Firstনিজেই ভাল হবে।


1
@ আরআরসিআরসিআর: বিল্ডার এবং বার্তা উভয় ক্ষেত্রে কেন এটি জেনেরিক হওয়া দরকার তা আমি মনে করি না। আমি নিশ্চিত যে আমার যদি এটির প্রয়োজন না হত তবে আমি সেই পথে নেমে যেতাম না :)
জন স্কিটি

1
@SayemAhmed: হ্যাঁ, এটা বাধা দেয় না যে ধরনের আপ মিশ দৃষ্টিভঙ্গি। আমি এই সম্পর্কে একটি নোট যোগ করব।
জন স্কিটি

1
"আমি আমার সি # পোর্ট প্রোটোকলবাফারগুলিতে অনুরূপ কিছু ব্যবহার করেছি" " তবে এটি আলাদা কারণ বিল্ডারদের উদাহরণ পদ্ধতি রয়েছে যা পরামিতি প্রকারের টাইপ দেয়। Enumকোনও উদাহরণ পদ্ধতি নেই যা প্যারামিটার প্রকারটি ফেরত দেয়।
newacct

1
@ জোনস্কিট: এনাম ক্লাস সবসময় অটোজেনারেটেড থাকায় আমি দাবি করছি যে class Enum<E>এটি সব ক্ষেত্রেই যথেষ্ট। জেনারিক্সে আপনার কেবলমাত্র আরও সীমাবদ্ধ বাউন্ড ব্যবহার করা উচিত যদি এটির ধরণের সুরক্ষা নিশ্চিত করা প্রয়োজন necessary
নিউএ্যাক্যাক্ট

1
@JonSkeet: এছাড়াও, যদি Enumউপশ্রেণী সবসময় স্বতঃজেনারেট করা হয় নি, একমাত্র কারণ আপনার যা দরকার হবে class Enum<E extends Enum<?>>ওভার class Enum<E>এক্সেস করার দক্ষতা ordinalজন্য compareTo()। যাইহোক, আপনি যদি এটির বিষয়ে চিন্তা করেন তবে ভাষার অদৃশ্যের দিক থেকে এটি বোঝা যায় না যে আপনি তাদের অধ্যাদেশের মাধ্যমে দুটি ভিন্ন ধরণের এনামকে তুলনা করতে পারবেন। অতএব, এর Enum.compareTo()ব্যবহারগুলি প্রয়োগ করা ordinalকেবলমাত্র Enumসাবক্লাসগুলি স্বয়ংক্রিয়ভাবে তৈরি হওয়ার প্রসঙ্গেই অর্থবোধ করে। আপনি যদি ম্যানুয়ালি সাবক্লাস করতে পারেন Enum, compareToসম্ভবত হতে হবে abstract
newacct

27

নীচে জাভা জেনেরিকস এবং সংগ্রহ বইটি থেকে ব্যাখ্যাটির একটি পরিবর্তিত সংস্করণ রয়েছে : আমরা একটি Enumঘোষণা করেছি

enum Season { WINTER, SPRING, SUMMER, FALL }

যা একটি শ্রেণিতে প্রসারিত হবে

final class Season extends ...

যেখানে ...Enums জন্য একরকম-parameterised বেস বর্গ হতে হয়। আসুন কী হতে হবে তা নিয়ে কাজ করা যাক। ভাল, এর জন্য প্রয়োজনীয়তার Seasonএকটি হ'ল এটি কার্যকর করা উচিত Comparable<Season>। সুতরাং আমরা প্রয়োজন যাচ্ছি

Season extends ... implements Comparable<Season>

আপনি এটির জন্য কী ব্যবহার ...করতে পারবেন এটি কাজ করার অনুমতি দেবে? প্রদত্ত যে এটির একটি প্যারামিটারাইজেশন হতে হবে Enum, একমাত্র পছন্দ হ'ল Enum<Season>যাতে আপনি তা করতে পারেন:

Season extends Enum<Season>
Enum<Season> implements Comparable<Season>

তাই Enumমত ধরনের parameterised হয় Season। অ্যাবস্ট্রাক্ট Seasonএবং আপনি পান যে প্যারামিটারটি Enumযে কোনও ধরণের যা সন্তুষ্ট

 E extends Enum<E>

মরিস নাফটালিন (সহ-লেখক, জাভা জেনারিক্স এবং সংগ্রহ)


1
@ নিউভ্যাক্ট ঠিক আছে, আমি এখনই এটি পেয়েছি: আপনি সমস্ত এনামগুলিকে এনাম <ই> এর উদাহরণ হতে চান, তাই না? (কারণ এগুলি যদি এনাম সাব টাইপের উদাহরণ হয় তবে উপরের যুক্তিটি প্রযোজ্য)
মরিস নাফটালিন

1
@ Newwacct আপনি কি Seasonপ্রয়োগগুলি জোর দিতে চান না Comparable<Season>?
মরিস নাফটালিন

2
এনওয়াম সংজ্ঞাটি দেখুন অন্য উদাহরণগুলির সাথে একটি উদাহরণের তুলনা করতে তাদের অধ্যাদেশগুলি তুলনা করতে হবে। সুতরাং compareToপদ্ধতির যুক্তিটি অবশ্যই একটি সাব টাইপ হিসাবে ঘোষণা করা হয়েছে Enum, বা সংকলকটি (সঠিকভাবে) বলবে যে এর কোনও অর্ডিনাল নেই।
মরিস নাফটালিন

2
@ মরিসনিফটালিন: জাভা যদি ম্যানুয়ালি সাবক্লাসিং নিষিদ্ধ না করে Enum, তবে এখনই class OneEnum extends Enum<AnotherEnum>{}কীভাবে Enumঘোষণা করা হয়েছে তা সত্ত্বেও এটি সম্ভব হবে । এটা অনেক অর্থে দেখা যায় না হবে অতএব অন্যের সঙ্গে enum এক ধরনের তুলনা করতে, পাবে Enums 'এর compareToহিসাবে যাহাই হউক না কেন ঘোষিত জানার জন্য না। সীমানা এটিতে কোনও সহায়তা দেয় না।
newacct

2
@ মরিসনাফটালিন: যদি অর্ডিনাল কারণ হয় তবে public class Enum<E extends Enum<?>>তাও যথেষ্ট ছিল।
newacct

6

এটি একটি সাধারণ উদাহরণ এবং এমন একটি কৌশল দ্বারা চিত্রিত করা যেতে পারে যা উপ-শ্রেণীর জন্য চেইন পদ্ধতিতে কল প্রয়োগ করতে ব্যবহার করা যেতে পারে। নীচে একটি উদাহরণে setNameএকটি Nodeশৃঙ্খলা ফেরৎ দেয় City:

class Node {
    String name;

    Node setName(String name) {
        this.name = name;
        return this;
    }
}

class City extends Node {
    int square;

    City setSquare(int square) {
        this.square = square;
        return this;
    }
}

public static void main(String[] args) {
    City city = new City()
        .setName("LA")
        .setSquare(100);    // won't compile, setName() returns Node
}

সুতরাং আমরা একটি জেনেরিক ঘোষণায় একটি উপ-শ্রেণীর রেফারেন্স করতে পারি, যাতে Cityএখন সঠিক টাইপটি ফিরে আসে:

abstract class Node<SELF extends Node<SELF>>{
    String name;

    SELF setName(String name) {
        this.name = name;
        return self();
    }

    protected abstract SELF self();
}

class City extends Node<City> {
    int square;

    City setSquare(int square) {
        this.square = square;
        return self();
    }

    @Override
    protected City self() {
        return this;
    }

    public static void main(String[] args) {
       City city = new City()
            .setName("LA")
            .setSquare(100);                 // ok!
    }
}

: আপনার সমাধান একটি অবারিত দিয়েছে return (CHILD) this;একটি getThis জোড়ার কথা বিবেচনা করুন () পদ্ধতি: protected CHILD getThis() { return this; } দেখুন: angelikalanger.com/GenericsFAQ/FAQSections/...
রোল্যান্ড

@ রোল্যান্ড একটি লিঙ্কের জন্য ধন্যবাদ, আমি এটি থেকে একটি ধারণা ধার নিয়েছি। আপনি কি আমাকে ব্যাখ্যা করতে পারেন বা কোনও নিবন্ধের নির্দেশ দিয়ে বলতে পারেন যে এই বিশেষ ক্ষেত্রে এটি কেন খারাপ অভ্যাস? লিঙ্কটিতে থাকা পদ্ধতির জন্য আরও বেশি টাইপিংয়ের প্রয়োজন হয় এবং এটি এ কারণেই আমি এড়িয়ে চলেছি তার মূল যুক্তি। আমি এই ক্ষেত্রে কাস্ট ত্রুটিগুলি কখনও দেখিনি + আমি জানি যে কিছু অনিবার্য কাস্ট ত্রুটি রয়েছে - যেমন যখন কোনও একাধিক ধরণের বস্তু একই সংগ্রহের জন্য সঞ্চয় করে। সুতরাং যদি চেক না করা ক্যাসটগুলি সমালোচনা না করে এবং কিছুটা জটিল নকশাকরণ ( Node<T>এটি হয় না) তবে সময় সাশ্রয় করতে আমি এগুলি উপেক্ষা করছি।
আন্দ্রে চ্যাশেভ

আপনার সম্পাদনাটি কিছু সিনট্যাকটিক চিনির যোগ করার আগে এর চেয়ে আলাদা নয়, বিবেচনা করুন যে নিম্নলিখিত কোডটি আসলে সংকলন করবে তবে রান টাইম ত্রুটি ছুঁড়ে ফেলবে: ode নোড <সিটি> নোড = নতুন নোড <সিটি> ()। সেটনাম ("নোড")। সেটস্কয়ার (১); j আপনি জাভা বাইট কোডের দিকে নজর দিলে আপনি দেখতে পাবেন টাইপ ইরেজরের কারণে স্টেটমেন্টটি return (SELF) this;সংকলিত হয়েছে return this;, তাই আপনি কেবল এটি ছেড়ে দিতে পারেন।
রোল্যান্ড

@ রোল্যান্ড ধন্যবাদ, আমার এটাই দরকার - আমি মুক্ত হয়ে গেলে উদাহরণটি আপডেট করবে।
আন্দ্রে চাশেভ

নিম্নলিখিত লিঙ্কটিও
রোল্যান্ড

3

এর অর্থ কী তা আপনি ভাবছেন না কেবল; দেখতে বিশৃংখল জাভা ব্লগ

"যদি কোনও শ্রেণি এই শ্রেণিটি প্রসারিত করে তবে এটি প্যারামিটার ই পাস করবে The পরামিতি ই এর সীমানা একটি শ্রেণীর জন্য যা এই প্যারামিটার ই এর সাথে এই শ্রেণিটি প্রসারিত করে"।


1

এই পোস্টটি 'পুনরাবৃত্ত জেনেরিক ধরণের' এই সমস্যাগুলি আমার কাছে সম্পূর্ণ ব্যাখ্যা করেছে। আমি কেবলমাত্র অন্য একটি কেস যুক্ত করতে চেয়েছিলাম যেখানে এই নির্দিষ্ট কাঠামোটি প্রয়োজনীয়।

মনে করুন জেনেরিক গ্রাফে আপনার জেনেরিক নোড রয়েছে:

public abstract class Node<T extends Node<T>>
{
    public void addNeighbor(T);

    public void addNeighbors(Collection<? extends T> nodes);

    public Collection<T> getNeighbor();
}

তারপরে আপনার বিশেষ ধরণের গ্রাফ থাকতে পারে:

public class City extends Node<City>
{
    public void addNeighbor(City){...}

    public void addNeighbors(Collection<? extends City> nodes){...}

    public Collection<City> getNeighbor(){...}
}

এটি এখনও আমাকে এমন একটি জায়গা তৈরি করতে দেয় class Foo extends Node<City>যেখানে ফু শহরের সাথে সম্পর্কিত নয়।
newacct

1
অবশ্যই, এবং এটা কি ভুল? আমি তাই মনে করি না. নোড <সিটি> দ্বারা সরবরাহিত বেস চুক্তিটি এখনও সম্মানিত, কেবলমাত্র আপনার ফু সাবক্লাস কম কার্যকর কারণ আপনি Foos এর সাথে কাজ শুরু করেন তবে শহরগুলিকে ADT এর বাইরে রাখেন। এর জন্য ব্যবহারের কেস থাকতে পারে তবে জেনেরিক প্যারামিটারটি কেবল সাবক্লাসের মতোই তৈরি করতে খুব সম্ভবত সহজ এবং আরও দরকারী। তবে যে কোনও উপায়ে ডিজাইনারের পছন্দ রয়েছে।
এমডিএমএ

@ এমডিএমএ: আমি সম্মত সুতরাং তারপর আবদ্ধ কি ব্যবহার করে, ঠিক উপরের class Node<T>?
newacct

1
@ নোজব্যাকল: আপনার উদাহরণটি প্রমাণ করে না যে "এই নির্দিষ্ট কাঠামোটি প্রয়োজনীয়"। class Node<T>আপনার উদাহরণের সাথে সম্পূর্ণ সুসংগত।
newacct

1

যদি আপনি Enumউত্স কোডটি দেখেন তবে এটিতে নিম্নলিখিতটি রয়েছে:

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {

    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }

    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }

    public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    } 
}

প্রথম জিনিস, E extends Enum<E>মানে কি? এর অর্থ টাইপ প্যারামিটার এমন কিছু যা এনাম থেকে প্রসারিত এবং কোনও কাঁচা ধরণের (প্যারামেট্রাইজড এটি নিজেই) দিয়ে প্যারামিটারাইজড হয় না।

আপনার যদি এনাম থাকে তবে এটি প্রাসঙ্গিক

public enum MyEnum {
    THING1,
    THING2;
}

যা আমি যদি সঠিকভাবে জানি তবে এটি অনুবাদ করা হয়েছে

public final class MyEnum extends Enum<MyEnum> {
    public static final MyEnum THING1 = new MyEnum();
    public static final MyEnum THING2 = new MyEnum();
}

সুতরাং এর অর্থ হ'ল মাইনাম নিম্নলিখিত পদ্ধতিগুলি গ্রহণ করে:

public final int compareTo(MyEnum o) {
    Enum<?> other = (Enum<?>)o;
    Enum<MyEnum> self = this;
    if (self.getClass() != other.getClass() && // optimization
        self.getDeclaringClass() != other.getDeclaringClass())
        throw new ClassCastException();
    return self.ordinal - other.ordinal;
}

এবং আরও গুরুত্বপূর্ণভাবে,

    @SuppressWarnings("unchecked")
    public final Class<MyEnum> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<MyEnum>)clazz : (Class<MyEnum>)zuper;
    }

এটি getDeclaringClass()যথাযথ Class<T>বস্তুতে কাস্ট করে তোলে ।

একটি উপায় পরিষ্কার উদাহরণ হ'ল আমি এই প্রশ্নের উত্তর দিয়েছি যেখানে আপনি জেনেরিক সীমা নির্দিষ্ট করতে চান তবে আপনি এই নির্মাণটি এড়াতে পারবেন না।


আপনি যে কিছুই দেখিয়েছেন compareToবা বাউন্ডের getDeclaringClassপ্রয়োজন নেই extends Enum<E>
newacct

0

উইকিপিডিয়া অনুসারে, এই প্যাটার্নটিকে কৌতূহলীভাবে পুনরাবৃত্তি টেম্পলেট প্যাটার্ন বলা হয় । মূলত, সিআরটিপি প্যাটার্ন ব্যবহার করে আমরা সহজেই টাইপ কাস্টিং ছাড়াই সাবক্লাস প্রকারের উল্লেখ করতে পারি, যার অর্থ প্যাটার্নটি ব্যবহার করে আমরা ভার্চুয়াল ফাংশনটি অনুকরণ করতে পারি।

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