জাভা - পলিমারফিজম বা সীমাবদ্ধ ধরণের পরামিতি ব্যবহার করুন


17

ধরুন আমার কাছে এই শ্রেণিবৃত্তি রয়েছে ...

public abstract class Animal {
    public abstract void eat();
    public abstract void talk();
}
class Dog extends Animal {
    @Override
    public void eat() {
    }

    @Override
    public void talk() {
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
    }

    @Override
    public void talk() {
    }
}

এবং তারপর আমি ...

public static <T extends Animal> void addAnimal(T animal) {
    animal.eat();
    animal.talk();
}

public static void addAnimalPoly(Animal animal) {
    animal.eat();
    animal.talk();
}

বাউন্ডেড টাইপ পরামিতি বা পলিমারফিজম ব্যবহার করার সময় কী পার্থক্য রয়েছে?

এবং কখন এক বা অন্যটি ব্যবহার করবেন?


1
এই দুটি সংজ্ঞা টাইপ পরামিতি থেকে বেশি লাভ করে না। তবে addAnimals(List<Animal>)বিড়ালের তালিকা লিখতে এবং যুক্ত করার চেষ্টা করুন !
কিলিয়ান ফট

7
ঠিক আছে, উদাহরণস্বরূপ, যদি আপনার উপরের প্রতিটি পদ্ধতির পাশাপাশি কিছু ফিরে আসে তবে জেনেরিকগুলি ব্যবহার করে সে টি ফিরে আসতে পারে, অন্যটি কেবলমাত্র প্রাণীটিকেই ফিরিয়ে দিতে পারে। সুতরাং সেই পদ্ধতিগুলির ব্যবহারকারী ব্যক্তির জন্য, প্রথম ক্ষেত্রে তিনি যা চান ঠিক তেমনই ফিরে আসতেন: ডড কুকুর = অ্যাডমিনিমাল (নতুন কুকুর ()); ২ য় পদ্ধতিতে কুকুরের জন্য তাকে নিক্ষেপ করতে বাধ্য করা হবে: কুকুর ডি = (কুকুর) #AnimalPoly (নতুন কুকুর ());
শিবান ড্রাগন

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

উত্তর:


14

এই দুটি উদাহরণ সমতুল্য এবং বাস্তবে একই বাইটকোডে সংকলন করবে।

আপনার প্রথম উদাহরণ হিসাবে একটি পদ্ধতিতে একটি সীমাবদ্ধ জেনেরিক প্রকার যুক্ত করা যে কোনও কিছু করবে এমন দুটি উপায় রয়েছে।

টাইপ প্যারামিটার অন্য ধরণের পাস করা

এই দুটি পদ্ধতির স্বাক্ষরগুলি বাইট কোডে একই হয়ে যায় তবে সংকলকটি সুরক্ষা কার্যকর করে:

public static <T extends Animal> void addAnimals(Collection<T> animals)

public static void addAnimals(Collection<Animal> animals)

প্রথম ক্ষেত্রে, কেবলমাত্র একটি Collection(বা উপ-টাইপ) Animalঅনুমোদিত। দ্বিতীয় ক্ষেত্রে, Collectionজেনেরিক ধরণের বা উপ-টাইপযুক্ত একটি (বা সাব টাইপ) Animalঅনুমোদিত।

উদাহরণস্বরূপ, নিম্নলিখিতটি প্রথম পদ্ধতিতে অনুমোদিত তবে দ্বিতীয়টি নয়:

List<Cat> cats = new ArrayList<Cat>();
cats.add(new Cat());
addAnimals(cats);

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

প্রত্যাবর্তন অবজেক্টস

অন্য সময় এটি গুরুত্বপূর্ণ জিনিসগুলি ফিরে আসার সাথে। আসুন ধরে নেওয়া যাক নিম্নলিখিত পদ্ধতিটি বিদ্যমান ছিল:

public static <T extends Animal> T feed(T animal) {
  animal.eat();
  return animal;
}

আপনি এটি দিয়ে নিম্নলিখিতটি করতে সক্ষম হবেন:

Cat c1 = new Cat();
Cat c2 = feed(c1);

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


" প্রথম ক্ষেত্রে, কেবলমাত্র প্রাণীর সংগ্রহ (বা উপ-টাইপ) অনুমোদিত। দ্বিতীয় ক্ষেত্রে, জেনেরিক প্রকারের প্রাণী বা উপ-টাইপের সহ একটি সংগ্রহ (বা উপ-টাইপ) অনুমোদিত। " - আপনি কি দ্বিগুণ করতে চান - সেখানে আপনার যুক্তি পরীক্ষা?
মনিকা'র মোকদ্দমা

3

ডাউন কাস্টিংয়ের পরিবর্তে জেনেরিক ব্যবহার করুন। "ডাউনকাস্টিং" খারাপ, আরও সাধারণ ধরণের থেকে আরও নির্দিষ্ট একটিতে চলে যায়:

Animal a = hunter.captureOne();
Cat c = (Cat)a;  // ACK!!!!!! What if it's a Dog? ClassCastException!

... আপনি বিশ্বাস করছেন যে aএটি একটি বিড়াল, তবে সংকলক এটির গ্যারান্টি দিতে পারে না। রানটাইমের সময় এটি কুকুর হতে পারে।

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

public class <A> Hunter() {
    public A captureOne() { ... }
}

এখন আপনি উল্লেখ করতে পারেন যে আপনি একটি বিড়াল শিকারী চান:

Hunter<Cat> hunterC = new Hunter<Cat>();
Cat c = hunterC.captureOne();

Hunter<Dog> hunterD = new Hunter<Dog>();
Dog d = hunterD.captureOne();

এখন কম্পাইলার করতে জনিত যে hunterC শুধুমাত্র বিড়াল ক্যাপচার করা হবে, এবং hunterD হবে শুধুমাত্র ক্যাপচার কুকুর।

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

অথবা, সত্যিই, যদি আপনি খুঁজে পেলেন যে আপনি হ্রাস করতে পারেন তবে জেনেরিকগুলি ব্যবহার করুন।

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

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

public class <T> Zoo() { ... }

Zoo<Sponge> spongeZoo = ...
Zoo<Cat> catZoo = ...

আপনি যে ডিগ্রিটি লক করে রেখেছেন তা নির্ভর করে আপনি যা করার চেষ্টা করছেন তার উপর;)


2

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

টি এল; ডিআর

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

সম্পূর্ণ উত্তর

বাউন্ডেড টাইপ প্যারামিটারগুলি উত্তরাধিকার সূত্রে প্রাপ্ত সদস্যের পরিবর্তনশীলের জন্য কংক্রিট, অ-উত্তরাধিকারসূত্রে সাবক্লাস পদ্ধতি উদ্ঘাটন করতে পারে। পলিমারফিজম পারে না

আপনার উদাহরণটি প্রসারিত করে বিস্তারিত বর্ণনা:

public abstract class AnimalOwner<T extends Animal> {
   protected T pet;
   public abstract void rewardPet();
}

// Modify the dog class
class Dog extends Animal {
   // ...
   // This method is not inherited from anywhere!
   public void scratchBelly() {
      System.out.println("Belly: Scratched");
   }
}

class DogOwner extends AnimalOwner<Dog> {
   DogOwner(Dog dog) {
     this.pet = dog;
   }

   @Override
   public void rewardPet()
   {
      // ---- Note this call ----
      pet.scratchBelly();
   }
}

যদি অ্যাবস্ট্রাক্ট ক্লাস অ্যানিমাল ওউনারকে পলিমারফিজমের protected Animal pet;জন্য এবং বেছে নেওয়ার জন্য সংজ্ঞায়িত করা হয়, তবে সংকলকটি pet.scratchBelly();লাইনে ত্রুটি করবে , আপনাকে জানায় যে এই পদ্ধতিটি পশুর জন্য অপরিজ্ঞাত।


1

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

এখানে এমন কিছু পরিস্থিতি রয়েছে যেখানে আপনি সীমাবদ্ধ ধরণের পরামিতি ব্যবহার করবেন:

  • সংগ্রহের পরামিতি

    class Zoo {
    
      private List<Animal> animals;
    
      public void add(Collection<? extends Animal> newAnimals) {
        animals.addAll(newAnimals);
      }
    }

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

    List<Dog> dogs = ...
    zoo.add(dogs);

    zoo.add(dogs)ব্যতীত সংকলন করতে ব্যর্থ হবে <? extends Animal>, কারণ জেনেরিকস কোভেরিয়েন্ট হয় না।

  • Subclassing

    abstract class Warrior<T extends Weapon> {
    
      public abstract T getWeapon();
    }

    টাইপ সাবক্লাস সরবরাহ করতে পারে সীমাবদ্ধ করতে।

<T extends A1 & A2 & A3>তালিকার সমস্ত প্রকারের একটি টাইপ একটি উপ-প্রকার তা নিশ্চিত করতে আপনি একাধিক সীমা ব্যবহার করতে পারেন ।

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