জেনেরিক ক্লাসে স্ট্যাটিক পদ্ধতি?


197

জাভাতে, আমি কিছু পেতে চাই:

class Clazz<T> {
  static void doIt(T object) {
    // ...
  }
}

তবে আমি পেয়েছি

অ-স্থির টাইপ টি-তে স্থির রেফারেন্স তৈরি করতে পারে না

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

কেউ কি একইরকম পদ্ধতিতে এই জাতীয় ব্যবহার সম্ভব কিনা তা স্পষ্ট করে বলতে পারেন? এছাড়াও, কেন আমার মূল প্রচেষ্টাটি ব্যর্থ হয়েছিল?

উত্তর:


270

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

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


9
উত্সাহিত, এই উত্তরটি কেবল একটি কর্মক্ষেত্র সরবরাহের পরিবর্তে পোস্টারের সমস্যাটি ব্যাখ্যা করে।
উয়র্ন

7
@ আন্ড্রে: আপনার অন্তর্নিহিত ভিত্তিহীন নয়; সি # সত্যই জেনারিকদের এইভাবে আচরণ করে।
জৈঙ্গদেব

32
"স্থিতিশীল ক্ষেত্র এবং স্থির পদ্ধতির জন্য, তারা শ্রেণীর সমস্ত উদাহরণগুলির মধ্যে ভাগ করা হয়, এমনকি বিভিন্ন ধরণের পরামিতিগুলির উদাহরণগুলিও ..." আচ্ছা! আবার বাদুড়িতে লাথি মেরে আবার মুছে ফেলা!
রিভেনহিল

2
আপনি যদি জেনেরিক শ্রেণি / পদ্ধতিগুলি সংকলনের পরে দেখেন তবে আপনি দেখতে পাবেন যে জেনেরিক গুণাবলী সরানো হয়েছে। এবং তালিকা <Integer> সংকলনের পরে "তালিকা" মনে হচ্ছে। সুতরাং তালিকা <<<> এবং তালিকা <দীর্ঘ> সংকলনের পরে আলাদা নয় - উভয়ই তালিকায় পরিণত হয়েছিল।
ডায়িনিয়াস

3
আমি মনে করি তিনি মোটামুটি ভাল করার চেষ্টা করছেন যা তিনি ব্যাখ্যা করেছিলেন। এটা স্পষ্ট যে তিনি ডেট লুঠ কাঁপানোর চেষ্টা করছেন! হাহ
এস্ট্রিক

140

Tআপনি কোনও প্রকারের ইনস্ট্যান্ট না করা পর্যন্ত জাভা জানেনা ।

সম্ভবত আপনি কল করে স্থিতিশীল পদ্ধতিগুলি সম্পাদন করতে পারেন Clazz<T>.doit(something)তবে মনে হচ্ছে আপনি পারবেন না।

জিনিসগুলি হ্যান্ডেল করার অন্য উপায়টি হ'ল পদ্ধতিতে প্যারামিটারটি টাইপ করা:

static <U> void doIt(U object)

যা আপনাকে ইউ তে সঠিক সীমাবদ্ধতা দেয় না, তবে এটি কোনও কিছুর চেয়ে ভাল ...


তারপরে আমি কোনও সীমাবদ্ধতা নির্দিষ্ট না করেই পদ্ধতিটি কল করতাম, যেমন ক্লাজ <ওজেক্ট> .ডো (অবজেক্ট) এর পরিবর্তে ক্ল্যাজ.ডো আইটি (অবজেক্ট)? আপনি ঠিক আছে বিবেচনা?
আন্ড্রে চেল্লা

দ্বিতীয় বাক্য গঠনটি আরও সঠিকভাবে রয়েছে, যা আপনার প্রয়োজন যদি সংকলক পদ্ধতিটি বলা হয় এমন কনটেক্সট থেকে রিটার্ন মানটির ধরণটি নির্ধারণ করতে না পারে। অন্য কথায়, সংকলক যদি Clazz.doIt (অবজেক্ট) এর অনুমতি দেয় তবে তা করুন।
স্কাফম্যান

1
আমি ক্লাজ << অবজেক্ট> .DO (বস্তু) চেষ্টা করেছিলাম এবং একটি সংকলন-সময় ত্রুটি পেয়েছি! "টোকেন (গুলি) এ সিনট্যাক্স ত্রুটি, ভুল জায়গায় নির্মাণ (গুলি)"। Clazz.doIt (অবজেক্ট) ভাল কাজ করে, এমনকি কোনও সতর্কতাও নয়।
আন্দ্রে চেল্লা

8
ক্লজ ব্যবহার করুন <<অবজেক্ট> doIt (অবজেক্ট)। আমি মনে করি এটি অদ্ভুত বাক্য গঠন, সি ++ এর ক্লাজ <<> :: doIt (1) এর সাথে তুলনা করে
ক্র্যান্ড কিং কিং

আপনি কেন বলছেন যে এটি আপনাকে ইউ এর উপর সঠিক বাধা দেয় না?
অ্যাডাম

46

আমি এই একই সমস্যা মধ্যে দৌড়ে। Collections.sortজাভা ফ্রেমওয়ার্কের জন্য সোর্স কোডটি ডাউনলোড করে আমার উত্তর খুঁজে পেয়েছি । আমি যে উত্তরটি ব্যবহার করেছি তা হ'ল <T>জেনেরিকটি পদ্ধতিতে শ্রেণি সংজ্ঞাতে নয় put

সুতরাং এটি কাজ করেছে:

public class QuickSortArray  {
    public static <T extends Comparable> void quickSort(T[] array, int bottom, int top){
//do it
}

}

অবশ্যই উপরের উত্তরগুলি পড়ার পরে আমি বুঝতে পেরেছিলাম যে জেনেরিক শ্রেণি ব্যবহার না করে এটি একটি গ্রহণযোগ্য বিকল্প হবে:

public static void quickSort(Comparable[] array, int bottom, int top){
//do it
}

8
যদিও গৃহীত উত্তরটি প্রযুক্তিগতভাবে সঠিক ছিল: গুগল যখন আমাকে এই প্রশ্নের দিকে নিয়ে গিয়েছিল তখন এটিই আমি খুঁজছিলাম।
জেরেমি তালিকা

T extends XXXসিনট্যাক্স অন্তর্ভুক্ত একটি উদাহরণ প্রদানের জন্য প্রপস ।
ওগ্রে গীতসংহিতা

3
@ ক্রিস আপনি যেহেতু জেনেরিক ব্যবহার করছেন তাই আপনি এগুলি সমস্ত উপায়ে ব্যবহার করতে পারেন --- যেমন কাঁচা ধরণের ব্যবহার না করা Comparable<T extends Comparable<? super T>>পরিবর্তে চেষ্টা করুন।
ইজোনকক্সz

15

আপনার doIt()পদ্ধতিটি ঘোষণা করার সময় জেনেরিক পদ্ধতির জন্য সিনট্যাক্স ব্যবহার করে আপনি যা চান তা করা সম্ভব ( পদ্ধতিটির স্বাক্ষরের <T>মধ্যে staticএবং এর মধ্যে সংযোজনটি লক্ষ্য করুন ):voiddoIt()

class Clazz<T> {
  static <T> void doIt(T object) {
    // shake that booty
  }
}

উপরের কোডটি Cannot make a static reference to the non-static type Tত্রুটি ছাড়াই গ্রহন করার জন্য আমি এক্লিপস সম্পাদক পেয়েছি এবং তারপরে এটি নীচের কার্যকারী প্রোগ্রামে প্রসারিত করেছি (কিছুটা বয়স-উপযুক্ত সাংস্কৃতিক রেফারেন্স সহ সম্পূর্ণ):

public class Clazz<T> {
  static <T> void doIt(T object) {
    System.out.println("shake that booty '" + object.getClass().toString()
                       + "' !!!");
  }

  private static class KC {
  }

  private static class SunshineBand {
  }

  public static void main(String args[]) {
    KC kc = new KC();
    SunshineBand sunshineBand = new SunshineBand();
    Clazz.doIt(kc);
    Clazz.doIt(sunshineBand);
  }
}

আমি যখন এটি চালাচ্ছি তখন কোন কনসোলে এই লাইনগুলি মুদ্রণ করে:

ঝাঁকুনি যে 'ক্লাস com.eclipseoptions.datamanager.Clazz $ KC' !!!
ঝাঁকুনি যে 'ক্লাস com.eclipseoptions.datamanager.Clazz $ সানশাইনব্যান্ড' !!!


এই ক্ষেত্রে, দ্বিতীয় <T> প্রথমটি কি লুকায়?
আন্দ্রে চেল্লা

1
@ অ্যান্ড্রিনিউজ, হ্যাঁ দ্বিতীয়টি <T>প্রথমটিকে একইভাবে মাস্ক করে যেভাবে class C { int x; C(int x) { ... } }প্যারামিটারে xক্ষেত্রটি মাস্ক করে x
মাইক স্যামুয়েল

নমুনার আউটপুট কীভাবে ব্যাখ্যা করবেন: মনে হচ্ছে সত্যই সেখানে দুটি প্রকার জড়িত রয়েছে, একটি প্যারামিটার টি মান দ্বারা? টি যদি সত্যিই ক্লাসের ধরণটি গোপন করে রাখত তবে আমি আশা করব "ঝাঁকুনি লুঠি 'ক্লাস com.eclipseoptions.datamanager.Clazz" পরামিতি ছাড়াই দু'বার আউটপুট হয়ে গেছে।
প্রাগমেটেক

1
মাস্কিংয়ের সাথে এর কোনও যোগসূত্র নেই। একটি স্ট্যাটিক পদ্ধতি কেবল ক্লাস জেনেরিক ধরণের দ্বারা আবদ্ধ হতে পারে না । তবুও এটি তার নিজস্ব জেনেরিক ধরণের এবং সীমানা সংজ্ঞায়িত করতে পারে।
মাইকে

স্ট্যাটিক টাইপটি একবারে সংজ্ঞায়িত করার এবং বেশ কয়েকটি স্থিতিশীল পদ্ধতির জন্য এটি পুনরায় ব্যবহার করার কোনও উপায় আছে কি? static <E extends SomeClass> E foo(E input){return input;}যখন আমি কিছু করতে চাই তখন আমি প্রতিটি এবং প্রতিটি পদ্ধতির জন্য অনুরাগী নইstatic <E extends SomeClass>; //static generic type defined only once and reused static E foo(E input){return input;} static E bar(E input){return input;} //...etc...
HesNotTheStig

14

আমি মনে করি এই বাক্য গঠনটি এখনও উল্লেখ করা হয়নি (ক্ষেত্রে আপনি যুক্তি ছাড়াই কোনও পদ্ধতি চান):

class Clazz {
  static <T> T doIt() {
    // shake that booty
  }
}

এবং কল:

String str = Clazz.<String>doIt();

আশা করি এটি কারও সাহায্য করবে।


1
আসলে (আমি জাভা সংস্করণ জানি না), এটি ছাড়াও এটি সম্ভব <String>কারণ এটি কেবল প্রকারের যুক্তিটিকেই অনুমান করে কারণ আপনি এটিকে ভেরিয়েবলের জন্য নির্ধারণ করেন। যদি আপনি এটি বরাদ্দ না করেন তবে এটি কেবল অনুমান করে Object
অ্যাডোরাথ

এটি একটি নিখুঁত সমাধান।
প্রভাত রঞ্জন

6

এটি সঠিকভাবে ভুলবশত উল্লেখ করা হয়: আপনি অ স্ট্যাটিক টাইপ টি করার জন্য একটি স্ট্যাটিক রেফারেন্স করতে পারবেন না কারণ নেই টাইপ প্যারামিটার Tটাইপ যুক্তি যেমন কোনো দ্বারা প্রতিস্থাপিত হতে পারে Clazz<String>বা Clazz<integer>ইত্যাদি কিন্তু স্ট্যাটিক ক্ষেত্র / পদ্ধতি সব অ দ্বারা ভাগ করা হয় ক্লাসের স্ট্যাটিক অবজেক্টস।

নিম্নলিখিত অংশটি ডক থেকে নেওয়া হয়েছে :

শ্রেণীর স্থির ক্ষেত্র হ'ল শ্রেণীর স্তরের পরিবর্তনশীল যা শ্রেণীর সমস্ত অ স্থিতিকাল বস্তু দ্বারা ভাগ করা হয়। সুতরাং, প্রকারের পরামিতিগুলির স্থির ক্ষেত্রগুলির অনুমতি নেই। নিম্নলিখিত শ্রেণীর বিবেচনা করুন:

public class MobileDevice<T> {
    private static T os;

    // ...
}

ধরণের পরামিতিগুলির স্থির ক্ষেত্রগুলিকে যদি অনুমতি দেওয়া হয় তবে নিম্নলিখিত কোডটি বিভ্রান্ত হবে:

MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> pc = new MobileDevice<>();

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

যথাযথভাবে তার উত্তরে খ্রিস্ট দ্বারা নির্দেশিতভাবে আপনাকে পদ্ধতিটির সাথে টাইপ পরামিতি ব্যবহার করতে হবে এবং এই ক্ষেত্রে ক্লাসের সাথে নয়। আপনি এটি লিখতে পারেন:

static <E> void doIt(E object) 

3

নীচের মতো কিছু আপনাকে নিবিড় করে তুলবে

class Clazz
{
   public static <U extends Clazz> void doIt(U thing)
   {
   }
}

সম্পাদনা: আরও বিশদ সহ আপডেট করা উদাহরণ

public abstract class Thingo 
{

    public static <U extends Thingo> void doIt(U p_thingo)
    {
        p_thingo.thing();
    }

    protected abstract void thing();

}

class SubThingoOne extends Thingo
{
    @Override
    protected void thing() 
    {
        System.out.println("SubThingoOne");
    }
}

class SubThingoTwo extends Thingo
{

    @Override
    protected void thing() 
    {
        System.out.println("SuThingoTwo");
    }

}

public class ThingoTest 
{

    @Test
    public void test() 
    {
        Thingo t1 = new SubThingoOne();
        Thingo t2 = new SubThingoTwo();

        Thingo.doIt(t1);
        Thingo.doIt(t2);

        // compile error -->  Thingo.doIt(new Object());
    }
}

ঠিক যেমনটি জেসন এস পরামর্শ দিয়েছেন।
আন্দ্রে চেল্লা

@ এর আগেও আগের পরামর্শটি আপনাকে এই বিধিনিষেধ দেয়নি যে আপনাকে অবশ্যই ক্লজ
বাড়াতে

আমি দেখছি, তবে এটি সীমাবদ্ধতা ব্যতীত দরকারী কিছু যুক্ত করে না। আমার মূল পোস্টে, আমি প্যারামিটার হিসাবে ইউ পাস না করে এটি করতে সক্ষম হতে চাই।
আন্দ্রে চেল্লা

@ আমার উপরে আপডেট দেখুন। জেনেরিক
ধরণটি

আপনাকে ধন্যবাদ, আমি এখন বুঝতে পেরেছি। দুঃখিত, আমি এই প্রশ্নটি তিন বছর আগে জিজ্ঞাসা করেছি, যখন আমি প্রতিদিন জাভা করছিলাম। আমি আপনার ধারণা পেয়েছি, যদিও আমি মনে করি আপনি বুঝতে পেরেছেন যে এটি মূলত আমি যা চেয়েছিলাম ঠিক তা নয়। তবে আপনার উত্তরটি আমার পছন্দ হয়েছে liked
আন্দ্রে চ্যালেলা

2

আপনি যখন আপনার ক্লাসের জন্য জেনেরিক টাইপ নির্দিষ্ট করেন, তখন জেভিএম এটি সম্পর্কে আপনার ক্লাসের উদাহরণ রয়েছে, সংজ্ঞা নয় know প্রতিটি সংজ্ঞায় কেবলমাত্র প্যারামিট্রাইজড প্রকার থাকে।

জেনেরিকস সি ++ তে টেম্পলেটগুলির মতো কাজ করে, তাই আপনার প্রথমে আপনার ক্লাসটি ইনস্ট্যান্ট করা উচিত, তারপরে নির্দিষ্ট ধরণের সাথে ফাংশনটি ব্যবহার করুন।


2
জাভা জেনেরিকগুলি সি ++ টেম্পলেটগুলির থেকে বেশ আলাদা different জেনেরিক ক্লাসটি নিজেই সংকলিত হয়। আসলে সি ++ এর সমমানের কোডটি কাজ করবে (কলিং কোডটি দেখতে দেখতে হবে Clazz<int>::doIt( 5 ))
ডেভিড রদ্রিগেজ - ড্রিবিস

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

1

এটিকে সহজ কথায় বলতে গেলে, এটি জেনেরিকের "ইরেজর" বৈশিষ্ট্যের কারণে ঘটে W যার অর্থ আমরা যদিও সংজ্ঞায়িত করি ArrayList<Integer>এবং ArrayList<String>সংকলনের সময় এটি দুটি পৃথক কংক্রিট ধরণের হিসাবে থাকে তবে রানটাইমগুলিতে জেভিএম জেনেরিক প্রকারগুলি মুছে দেয় এবং দুটি ক্লাসের পরিবর্তে একটি মাত্র অ্যারেলিস্ট ক্লাস তৈরি করে। সুতরাং যখন আমরা একটি জেনেরিক জন্য একটি স্ট্যাটিক টাইপ পদ্ধতি বা কিছু সংজ্ঞায়িত, এটা যে জেনেরিক সমস্ত উদাহরণ দ্বারা ভাগ করা, আমার উদাহরণে এটি উভয় দ্বারা ভাগ করা ArrayList<Integer>এবং ArrayList<String>.That কেন আপনি একটি ক্লাস হয় না error.A জেনেরিক প্রকার প্যারামিটার পেতে একটি স্থিতিশীল প্রসঙ্গে অনুমোদিত!


1

রিভেনহিলের @ বিডি: যেহেতু এই পুরানো প্রশ্নটি গত বছর নতুন করে দৃষ্টি আকর্ষণ করেছে, কেবল আলোচনার জন্য আসুন আমরা কিছুটা এগিয়ে যাই। আপনার doItপদ্ধতির বডিটি কিছু-বিশেষ কিছু করে না T। এটা এখানে:

public class Clazz<T> {
  static <T> void doIt(T object) {
    System.out.println("shake that booty '" + object.getClass().toString()
                       + "' !!!");
  }
// ...
}

সুতরাং আপনি সমস্ত ধরণের ভেরিয়েবল এবং জাস্ট কোড সম্পূর্ণরূপে বাদ দিতে পারেন

public class Clazz {
  static void doIt(Object object) {
    System.out.println("shake that booty '" + object.getClass().toString()
                       + "' !!!");
  }
// ...
}

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

public class Clazz  {
  static <T extends Saying> void doIt(T object) {
    System.out.println("shake that booty "+ object.say());
  }

  public static void main(String args[]) {
    Clazz.doIt(new KC());
    Clazz.doIt(new SunshineBand());
  }
}
// Output:
// KC
// Sunshine

interface Saying {
      public String say();
}

class KC implements Saying {
      public String say() {
          return "KC";
      }
}

class SunshineBand implements Saying {
      public String say() {
          return "Sunshine";
      }
}

তবে নিম্নলিখিত সংস্করণটি ঠিক একইভাবে কাজ করে, এগুলি কিছুই সম্পর্কে খুব বেশি হট্টগোল হয়। এটির জন্য যা দরকার তা হ'ল পদ্ধতি প্যারামিটারের ইন্টারফেস টাইপ। দৃষ্টিতে কোনও ধরণের ভেরিয়েবল নেই। আসলেই কি আসল সমস্যা ছিল?

public class Clazz  {
  static void doIt(Saying object) {
    System.out.println("shake that booty "+ object.say());
  }

  public static void main(String args[]) {
    Clazz.doIt(new KC());
    Clazz.doIt(new SunshineBand());
  }
}

interface Saying {
      public String say();
}

class KC implements Saying {
      public String say() {
          return "KC";
      }
}

class SunshineBand implements Saying {
      public String say() {
          return "Sunshine";
      }
}

0

স্ট্যাটিক ভেরিয়েবলগুলি ক্লাসের সমস্ত দৃষ্টান্ত দ্বারা ভাগ করা হয়। উদাহরণস্বরূপ যদি আপনার নিম্নলিখিত কোড রয়েছে

class Class<T> {
  static void doIt(T object) {
    // using T here 
  }
}

টি কেবলমাত্র একটি উদাহরণ তৈরির পরে উপলব্ধ। তবে দৃষ্টান্তগুলি উপলভ্য হওয়ার আগেই স্থির পদ্ধতি ব্যবহার করা যেতে পারে। সুতরাং, জেনেরিক ধরণের প্যারামিটারগুলি স্থির পদ্ধতি এবং ভেরিয়েবলের মধ্যে উল্লেখ করা যায় না

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