জেনেরিক পদ্ধতি কখন এবং কখন ওয়াইল্ড কার্ড ব্যবহার করবেন?


122

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

interface Collection<E> {
    public boolean containsAll(Collection<?> c);
    public boolean addAll(Collection<? extends E> c);
}

পরিবর্তে আমরা এখানে জেনেরিক পদ্ধতি ব্যবহার করতে পারতাম:

interface Collection<E> {
    public <T> boolean containsAll(Collection<T> c);
    public <T extends E> boolean addAll(Collection<T> c);
    // Hey, type variables can have bounds too!
}

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

আমরা কি মনে করি না ওয়াইল্ড কার্ডের মতো (Collection<? extends E> c); একধরণের পলিমারফিজমকে সমর্থন করে? তাহলে কেন জেনেরিক পদ্ধতির ব্যবহার এটিকে ভাল না বলে বিবেচনা করা হয়?

এগিয়ে চালিয়ে, এটিতে বলা হয়েছে,

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

এটার মানে কি?

তারা উদাহরণ উপস্থাপন করেছেন

class Collections {
    public static <T> void copy(List<T> dest, List<? extends T> src) {
    ...
}

[...]

আমরা ওয়াইল্ডকার্ড ব্যবহার না করেই এই পদ্ধতির জন্য স্বাক্ষরটি অন্য কোনওভাবে লিখতে পারতাম:

class Collections {
    public static <T, S extends T> void copy(List<T> dest, List<S> src) {
    ...
}

দস্তাবেজটি দ্বিতীয় ঘোষণাকে নিরুৎসাহিত করে এবং প্রথম সিনট্যাক্সের ব্যবহারকে উত্সাহ দেয়? প্রথম এবং দ্বিতীয় ঘোষণার মধ্যে পার্থক্য কী? দুজনেই কি একই কাজ করছে বলে মনে হচ্ছে?

এই অঞ্চলটিতে কেউ আলোকপাত করতে পারে।

উত্তর:


173

কিছু নির্দিষ্ট জায়গা আছে যেখানে ওয়াইল্ডকার্ড এবং টাইপ পরামিতি একই কাজ করে। তবে নির্দিষ্ট কিছু জায়গা রয়েছে যেখানে আপনাকে টাইপ পরামিতি ব্যবহার করতে হবে।

  1. আপনি যদি বিভিন্ন ধরণের পদ্ধতির আর্গুমেন্টের সাথে কিছু সম্পর্ক প্রয়োগ করতে চান তবে আপনি ওয়াইল্ডকার্ডের সাহায্যে এটি করতে পারবেন না, আপনাকে টাইপ পরামিতি ব্যবহার করতে হবে।

আপনার পদ্ধতির উদাহরণ হিসাবে ধরুন, ধরুন আপনি নিশ্চিত করতে চান যে পদ্ধতিতে পাস srcএবং destতালিকাটি copy()একই প্যারামিটারাইজড ধরণের হওয়া উচিত, আপনি টাইপ প্যারামিটারগুলির সাথে এটি করতে পারেন:

public static <T extends Number> void copy(List<T> dest, List<T> src)

এখানে, আপনি উভয় destএবং srcএকই প্যারামিটারাইজড টাইপ আছে তা নিশ্চিত List। সুতরাং, এটা থেকে উপাদানগুলি অনুলিপি করতে নিরাপদ srcকরার জন্য dest

তবে, যদি আপনি ওয়াইল্ডকার্ড ব্যবহারের পদ্ধতিটি পরিবর্তন করেন:

public static void copy(List<? extends Number> dest, List<? extends Number> src)

এটি প্রত্যাশার মতো কাজ করবে না। ২ য় ক্ষেত্রে, আপনি পাস করতে পারেন List<Integer>এবং List<Float>হিসাবে destএবং src। সুতরাং, থেকে উপাদানগুলি চলন্ত srcথেকে destআর নিরাপদ নয় টাইপ করা হবে। আপনার যদি এ জাতীয় সম্পর্কের প্রয়োজন না হয় তবে আপনি কোনও ধরণের পরামিতি ব্যবহার না করেই মুক্ত।

ওয়াইল্ডকার্ড এবং টাইপ পরামিতি ব্যবহারের মধ্যে কিছু অন্যান্য পার্থক্য হ'ল:

  • আপনার যদি কেবল একটি প্যারামিটারাইজড টাইপের আর্গুমেন্ট থাকে তবে আপনি ওয়াইল্ডকার্ড ব্যবহার করতে পারেন, যদিও টাইপ প্যারামিটারটিও কাজ করবে।
  • টাইপ পরামিতি একাধিক সীমা সমর্থন করে, ওয়াইল্ডকার্ডগুলি না don't
  • ওয়াইল্ডকার্ডগুলি উপরের এবং নিম্ন উভয় সীমানাকে সমর্থন করে, টাইপ পরামিতিগুলি কেবল উপরের সীমানাকে সমর্থন করে। সুতরাং, আপনি যদি এমন কোনও পদ্ধতি নির্ধারণ করতে চান যা Listবিভিন্ন ধরণের লাগে Integerবা এটি সুপার ক্লাস হয় তবে আপনি এটি করতে পারেন:

    public void print(List<? super Integer> list)  // OK

    তবে আপনি টাইপ প্যারামিটার ব্যবহার করতে পারবেন না:

     public <T super Integer> void print(List<T> list)  // Won't compile

তথ্যসূত্র:


1
এটি অদ্ভুত উত্তর। আপনাকে কেন মোটেও ব্যবহারের প্রয়োজন তা এটি ব্যাখ্যা করে না ?। আপনি এটিকে পুনরায় লিখতে পারবেন `পাবলিক স্ট্যাটিক <টি 1 প্রসারিত সংখ্যা, টি 2 বিস্তৃত সংখ্যা> শূন্য অনুলিপি (তালিকা <T1> ভাগ্য, তালিকা <T2> src) এবং এই ক্ষেত্রে এটি স্পষ্ট হয়ে ওঠে যা চলছে।
কান

@kan। আচ্ছা আসল বিষয়টি issue আপনি একই ধরণের প্রয়োগ করতে টাইপ প্যারামিটার ব্যবহার করতে পারেন তবে ওয়াইল্ডকার্ডগুলি দিয়ে আপনি এটি করতে পারবেন না। টাইপ প্যারামিটারের জন্য দুটি ভিন্ন ধরণের ব্যবহার করা আলাদা জিনিস।
রোহিত জৈন

1
@benz। আপনি কোনও Listপ্রকারের প্যারামিটার ব্যবহার করে নিম্ন সীমানা নির্ধারণ করতে পারবেন না । List<T super Integer>বৈধ নয়, এবং সংকলন করবে না।
রোহিত জৈন

2
@benz। আপনাকে স্বাগত জানাই :) আমি আপনাকে শেষ পর্যন্ত পোস্ট করা লিঙ্কটি দিয়ে যাওয়ার পরামর্শ দিচ্ছি। এটি জেনারিক্সের সেরা উত্স আপনি পাবেন।
রোহিত জৈন

3
@ jorgen.ringen <T extends X & Y>-> একাধিক সীমা।
রোহিত জৈন

12

নীচে জেমস গোসলিংয়ের জাভা প্রোগ্রামিংয়ের নীচের উদাহরণটি বিবেচনা করুন যেখানে নীচে আমরা 2 সিঙ্গললিঙ্ককিউতে মার্জ করতে চাই:

public static <T1, T2 extends T1> void merge(SinglyLinkQueue<T1> d, SinglyLinkQueue<T2> s){
    // merge s element into d
}

public static <T> void merge(SinglyLinkQueue<T> d, SinglyLinkQueue<? extends T> s){
        // merge s element into d
}

উপরোক্ত দুটি পদ্ধতিরই একই কার্যকারিতা রয়েছে। তাহলে কোনটি পছন্দনীয়? উত্তর দ্বিতীয় এক। লেখকের নিজস্ব কথায়:

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

দ্রষ্টব্য: বইটিতে কেবলমাত্র দ্বিতীয় পদ্ধতি দেওয়া হয়েছে এবং টাইপের পরামিতির নাম 'T' এর পরিবর্তে এস। প্রথম পদ্ধতি বইটিতে নেই।


আমি একটি বইয়ের উদ্ধৃতি দিয়েছিলাম, এটি প্রত্যক্ষ এবং সংক্ষিপ্ত
কুরাপিকা

9

আপনার প্রথম প্রশ্নে: এর অর্থ হ'ল যদি প্যারামিটারের ধরণ এবং পদ্ধতির রিটার্ন টাইপের মধ্যে কোনও সম্পর্ক থাকে তবে জেনেরিকটি ব্যবহার করুন।

উদাহরণ স্বরূপ:

public <T> T giveMeMaximum(Collection<T> items);
public <T> Collection<T> applyFilter(Collection<T> items);

এখানে আপনি নির্দিষ্ট মানদণ্ড অনুসরণ করে কিছু টি বের করছেন। টি হলে Longআপনার পদ্ধতিগুলি ফিরে আসবে Longএবং Collection<Long>; প্রকৃত রিটার্ন টাইপটি প্যারামিটার ধরণের উপর নির্ভরশীল, সুতরাং এটি জেনেরিক প্রকারগুলি ব্যবহার করার জন্য কার্যকর এবং পরামর্শ দেওয়া হয়।

যখন এটি না হয় আপনি ওয়াইল্ড কার্ডের ধরণগুলি ব্যবহার করতে পারেন:

public int count(Collection<?> items);
public boolean containsDuplicate(Collection<?> items);

এই দুটি উদাহরণে সংগ্রহের আইটেমগুলির প্রকারের রিটার্নের ধরণগুলি হ'ল intএবং boolean

আপনার উদাহরণগুলিতে:

interface Collection<E> {
    public boolean containsAll(Collection<?> c);
    public boolean addAll(Collection<? extends E> c);
}

এই দুটি ফাংশন সংগ্রহে আইটেমের ধরণের যা কিছু হোক না কেন একটি বুলিয়ান ফিরিয়ে দেবে। দ্বিতীয় ক্ষেত্রে এটি E এর একটি সাবক্লাসের উদাহরণের মধ্যে সীমাবদ্ধ is

দ্বিতীয় প্রশ্ন:

class Collections {
    public static <T> void copy(List<T> dest, List<? extends T> src) {
    ...
}

এই প্রথম কোডটি আপনাকে List<? extends T> srcপ্যারামিটার হিসাবে একটি ভিন্ন ভিন্ন পাস করার অনুমতি দেয় । এই তালিকায় বিভিন্ন শ্রেণীর একাধিক উপাদান থাকতে পারে যতক্ষণ না তারা সমস্ত বেস শ্রেণিকে প্রসারিত করে as

তোমার যদি থাকত:

interface Fruit{}

এবং

class Apple implements Fruit{}
class Pear implements Fruit{}
class Tomato implements Fruit{}

আপনি করতে পারে

List<? extends Fruit> basket = new ArrayList<? extends Fruit>();
basket.add(new Apple());
basket.add(new Pear());
basket.add(new Tomato());
List<Fruit> fridge = new ArrayList<Fruit>(); 

Collections.copy(fridge, basket);// works 

অন্য দিকে

class Collections {
    public static <T, S extends T> void copy(List<T> dest, List<S> src) {
    ...
}

টির List<S> srcএকটি সাবক্লাস হ'ল একটি নির্দিষ্ট শ্রেণির এসের সীমাবদ্ধতা list আপনি আমার আগের উদাহরণটি ব্যবহার করতে সক্ষম হবেন না তবে আপনি এটি করতে পারেন:

List<Apple> basket = new ArrayList<Apple>();
basket.add(new Apple());
basket.add(new Apple());
basket.add(new Apple());
List<Fruit> fridge = new ArrayList<Fruit>();

Collections.copy(fridge, basket); /* works since the basket is defined as a List of apples and not a list of some fruits. */

1
List<? extends Fruit> basket = new ArrayList<? extends Fruit>();একটি বৈধ বাক্য গঠন নয়। আপনাকে সীমা ছাড়াই অ্যারেলিস্ট ইনস্ট্যান্ট করতে হবে।
আর্নল্ড পিস্তোরিয়াস

উপরের উদাহরণে ঝুড়িতে কোনও আপেল যুক্ত করা যায় না যেহেতু ঝুড়ি নাশপাতিদের একটি তালিকা হতে পারে। ভুল উদাহরণ AFAIK। এবং পাশাপাশি সংকলন না।
খান্না 111

1
@ আর্নল্ডপিসটোরিয়াস যা আমাকে বিভ্রান্ত করে। আমি অ্যারেলিস্টের এপিআই ডকুমেন্টেশন চেক করেছি এবং এতে একজন কনস্ট্রাক্টর স্বাক্ষরিত হয়েছে ArrayList(Collection<? extends E> c)। আপনি আমাকে কেন ব্যাখ্যা করতে পারেন আপনি কেন এমন বলেছেন?
কুরাপিকা

@ কুরপিকা কি এমন হতে পারে যে আমি একটি পুরানো জাভা সংস্করণ ব্যবহার করছিলাম? কমেন্ট প্রায় 3 বছর আগে পোস্ট করা হয়েছিল।
আর্নল্ড পিস্তোরিয়াস

2

ওয়াইল্ডকার্ড পদ্ধতিটিও জেনেরিক - আপনি এটি বিভিন্ন ধরণের প্রকারের সাথে কল করতে পারেন।

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

তদতিরিক্ত, ?আপনি যখন কোনও ক্ষেত্র ঘোষণা করেন তখন সিনট্যাক্সটি এড়ানো যায় না:

class NumberContainer
{
 Set<? extends Number> numbers;
}

3
এটি কি কোনও মন্তব্য হওয়ার কথা নয়?
বুহাকে সিন্ধি

@ বুহাকেসিন্ডি দুঃখিত, অস্পষ্ট কোনটি? কেন -1? আমি মনে করি এটি প্রশ্নের উত্তর দেয়।
কান

2

আমি এক এক করে আপনার প্রশ্নের উত্তর দিয়েছি।

আমাদের কি মনে হয় না যে ওয়াইল্ড কার্ডও (Collection<? extends E> c);একধরণের পলিমারফিজমকে সমর্থন করে?

না। কারণ হ'ল সীমানা ওয়াইল্ডকার্ডের কোনও নির্দিষ্ট পরামিতি টাইপ নেই has এটি অজানা। এগুলি "জানে" সমস্তটি হ'ল "সংশ্লেষ" কোনও প্রকারের E(যে কোনও সংজ্ঞায়িত)। সুতরাং, এটি প্রদত্ত মান সীমানা প্রকারের সাথে মেলে কিনা তা যাচাই ও ন্যায়সঙ্গত করতে পারে না।

সুতরাং, ওয়াইল্ডকার্ডগুলিতে পলিমারফিক আচরণগুলি বোধগম্য নয়।

দস্তাবেজটি দ্বিতীয় ঘোষণাকে নিরুৎসাহিত করে এবং প্রথম সিনট্যাক্সের ব্যবহারকে উত্সাহ দেয়? প্রথম এবং দ্বিতীয় ঘোষণার মধ্যে পার্থক্য কী? দুজনেই কি একই কাজ করছে বলে মনে হচ্ছে?

Tসর্বদা সীমাবদ্ধ যেমন প্রথম বিকল্পটি এই ক্ষেত্রে আরও ভাল andsource অবশ্যই সাবক্লাসগুলির মান (অজানা) থাকবে T

সুতরাং, ধরুন যে আপনি সমস্ত সংখ্যার তালিকা অনুলিপি করতে চান, প্রথম বিকল্পটি হবে

Collections.copy(List<Number> dest, List<? extends Number> src);

src, মূলত, গ্রহণ করতে পারে List<Double>,List<Float> ইত্যাদি আছে করার স্থিতিমাপ টাইপ পাওয়া একটি ঊর্ধ্ব আবদ্ধ dest

2 য় বিকল্পটি আপনাকে Sপ্রতিলিপি করতে চান এমন প্রতিটি ধরণের জন্য আপনাকে বাধ্য করতে বাধ্য করবে

//For double 
Collections.copy(List<Number> dest, List<Double> src); //Double extends Number.

//For int
Collections.copy(List<Number> dest, List<Integer> src); //Integer extends Number.

যেমন S স্থিতিমাপ কর যে ধরনের বাঁধাই প্রয়োজন।

আশা করি এটা কাজে লাগবে.


আপনার শেষ অনুচ্ছেদে কী বোঝাতে চেয়েছেন তা ব্যাখ্যা করতে পারেন
বেনজ

যেটি ২ য় বিকল্প বলছে সেটি আপনাকে একটি বাঁধতে বাধ্য করবে ...... আপনি কি এটির বিস্তারিত ব্যাখ্যা করতে পারেন
বেনজ

<S extends T>বলে যে Sস্থিতিমাপ কর ধরনের উপশ্রেণী হল T, তাই এটি একটি স্থিতিমাপ প্রকার (কোনোওয়াইল্ডকার্ড) এর উপশ্রেণী যে প্রয়োজন T
বুহাকে সিন্ধি

2

অন্য একটি পার্থক্য যা এখানে তালিকাভুক্ত নয়।

static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
    for (T o : a) {
        c.add(o); // correct
    }
}

তবে নিম্নলিখিতগুলির ফলে সংকলন সময় ত্রুটি হবে।

static <T> void fromArrayToCollection(T[] a, Collection<?> c) {
    for (T o : a) {
        c.add(o); // compile time error
    }
}

0

আমি যতদূর বুঝতে পেরেছি, সেখানে কেবলমাত্র একটি ব্যবহারের কেস রয়েছে যখন ওয়াইল্ডকার্ডের কঠোর প্রয়োজন হয় (অর্থাত্ এমন কিছু প্রকাশ করতে পারেন যা আপনি স্পষ্ট ধরনের ধরণের পরামিতি ব্যবহার করে প্রকাশ করতে পারবেন না)। এটি যখন আপনার একটি নিম্ন সীমা নির্দিষ্ট করতে হবে।

এগুলি ছাড়াও ওয়াইল্ডকার্ডগুলি আরও সংক্ষিপ্ত কোড লিখতে পরিবেশন করে, যেমনটি আপনি উল্লেখ করেছেন নথিতে নিম্নলিখিত বিবৃতি দ্বারা বর্ণিত:

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

[...]

স্পষ্ট ধরণের পরামিতিগুলি ঘোষণার চেয়ে ওয়াইল্ডকার্ডগুলি ব্যবহার করা আরও স্পষ্ট এবং সংক্ষিপ্ত এবং তাই যখনই সম্ভব সম্ভব হওয়া উচিত।

[...]

ওয়াইল্ডকার্ডেরও সুবিধা রয়েছে যে তারা ক্ষেত্রের ধরন, স্থানীয় ভেরিয়েবল এবং অ্যারে হিসাবে পদ্ধতি স্বাক্ষরের বাইরে ব্যবহার করতে পারেন।


0

মূলত -> ওয়াইল্ডকার্ডস একটি জেনারিক পদ্ধতির প্যারামিটার / আর্গুমেন্ট স্তরে জেনেরিকগুলি প্রয়োগ করে। বিঃদ্রঃ. এটি ডিফল্টরূপে জেনেরিক ম্যাথোডেও করা যায়, তবে এখানে পরিবর্তে? আমরা নিজেই টি ব্যবহার করতে পারি।

প্যাকেজ জেনেরিক্স;

public class DemoWildCard {


    public static void main(String[] args) {
        DemoWildCard obj = new DemoWildCard();

        obj.display(new Person<Integer>());
        obj.display(new Person<String>());

    }

    void display(Person<?> person) {
        //allows person of Integer,String or anything
        //This cannnot be done if we use T, because in that case we have to make this method itself generic
        System.out.println(person);
    }

}

class Person<T>{

}

এসও ওয়াইল্ডকার্ডের নির্দিষ্ট ব্যবহারের ক্ষেত্রে এটি রয়েছে।

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