আমি কীভাবে পদ্ধতিটি রিটার্ন টাইপ জেনেরিক করব?


588

এই উদাহরণটি বিবেচনা করুন (ওওপি বইতে সাধারণত):

আমার একটি Animalক্লাস আছে, যেখানে প্রত্যেকের Animalঅনেক বন্ধু থাকতে পারে।
আর উপশ্রেণী পছন্দ Dog, Duck, Mouseইত্যাদি যা মতো নির্দিষ্ট আচরণ যোগ bark(), quack()ইত্যাদি

এখানে Animalক্লাস:

public class Animal {
    private Map<String,Animal> friends = new HashMap<>();

    public void addFriend(String name, Animal animal){
        friends.put(name,animal);
    }

    public Animal callFriend(String name){
        return friends.get(name);
    }
}

এবং প্রচুর টাইপকাস্টিং সহ কয়েকটি কোড স্নিপেট এখানে রয়েছে:

Mouse jerry = new Mouse();
jerry.addFriend("spike", new Dog());
jerry.addFriend("quacker", new Duck());

((Dog) jerry.callFriend("spike")).bark();
((Duck) jerry.callFriend("quacker")).quack();

টাইপকাস্টিং থেকে মুক্তি পেতে আমি রিটার্ন টাইপের জন্য জেনেরিকগুলি ব্যবহার করার কোনও উপায় নেই, যাতে আমি বলতে পারি

jerry.callFriend("spike").bark();
jerry.callFriend("quacker").quack();

রিটার্ন টাইপের কিছু প্রাথমিক কোডটি প্যারামিটার হিসাবে পদ্ধতিতে পৌঁছে দেওয়া হয়েছে যা কখনই ব্যবহৃত হয় না।

public<T extends Animal> T callFriend(String name, T unusedTypeObj){
    return (T)friends.get(name);        
}

অতিরিক্ত প্যারামিটার ব্যবহার না করে রানটাইনে রিটার্নের ধরণটি বের করার কোনও উপায় আছে কি instanceof? বা কমপক্ষে একটি ডামি উদাহরণের পরিবর্তে ধরণের শ্রেণি পাস করে।
আমি বুঝতে পারি জেনেরিকগুলি টাইপ-টাইপ-টাইপ পরীক্ষা করার জন্য, তবে এটির জন্য কি কোনও কার্যকারিতা রয়েছে?

উত্তর:


902

আপনি callFriendএইভাবে সংজ্ঞা দিতে পারেন :

public <T extends Animal> T callFriend(String name, Class<T> type) {
    return type.cast(friends.get(name));
}

তারপরে এটিকে কল করুন:

jerry.callFriend("spike", Dog.class).bark();
jerry.callFriend("quacker", Duck.class).quack();

এই কোডটিতে কোনও সংকলক সতর্কতা তৈরি না করার সুবিধা রয়েছে। অবশ্যই এটি প্রাক-জেনেরিক দিনগুলি থেকে কাস্টিংয়ের কেবলমাত্র একটি আপডেট সংস্করণ এবং কোনও অতিরিক্ত সুরক্ষা যোগ করে না।


29
... তবে কলফ্রেন্ড () কলের পরামিতিগুলির মধ্যে এখনও কোনও সংকলন টাইম চেকিং নেই।
ডেভিড স্মিট

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

@ জায়েদার, একেবারে একই নয় তবে এটি কাজ করবে: // এনিমাল ক্লাস পাবলিক টি কলফ্রেন্ড <T> (স্ট্রিং নাম) যেখানে টি: অ্যানিম্যাল friends বন্ধুদের [নাম] টি হিসাবে টি; } // কলিং ক্লাসের জেরি C কলফ্রেন্ড <ডগ> ("স্পাইক") B বার্ক (); jerry.CallFriend <হাঁসের> ( "quacker") হাতুড়ে ()।
নেস্টার লেডন

124

না। সংকলক জানতে পারে না কী প্রকারটি jerry.callFriend("spike")ফিরে আসবে। এছাড়াও, আপনার বাস্তবায়ন কোনও অতিরিক্ত ধরণের সুরক্ষা ছাড়াই পদ্ধতিতে castালাইটি লুকিয়ে রাখে। এই বিবেচনা:

jerry.addFriend("quaker", new Duck());
jerry.callFriend("quaker", /* unused */ new Dog()); // dies with illegal cast

এই নির্দিষ্ট ক্ষেত্রে, একটি বিমূর্ত talk()পদ্ধতি তৈরি করা এবং সাবক্লাসগুলিতে এটি যথাযথভাবে ওভাররাইড করা আপনাকে আরও ভালভাবে পরিবেশন করবে:

Mouse jerry = new Mouse();
jerry.addFriend("spike", new Dog());
jerry.addFriend("quacker", new Duck());

jerry.callFriend("spike").talk();
jerry.callFriend("quacker").talk();

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

1
একই ফলাফলটি অর্জনের এটি সঠিক উপায়। লক্ষ্য করুন লক্ষ্যটি কুৎসিত ধরণের চেকিং এবং ingালাই করার জন্য নিজেকে স্পষ্টভাবে কোড না লিখে রানটাইমে ক্লাস নির্দিষ্ট আচরণ প্রাপ্ত করা। @ ল্যাজের প্রস্তাবিত পদ্ধতিটি কাজ করে, তবে উইন্ডোটি থেকে সুরক্ষা প্রকারে ফেলে দেয়। এই পদ্ধতিতে কোডের কম রেখাগুলি প্রয়োজন (কারণ পদ্ধতি প্রয়োগগুলি দেরীতে আবদ্ধ এবং যাইহোক রানটাইমটিতে সন্ধান করা হয়) তবে তবুও আপনি সহজেই প্রাণীর প্রতিটি সাবক্লাসের জন্য অনন্য আচরণের সংজ্ঞা দিন।
ডিসকো

তবে আসল প্রশ্নটি টাইপ সুরক্ষা সম্পর্কে জিজ্ঞাসা করছে না। আমি এটি যেভাবে পড়ি তা জিজ্ঞাসাবাদী কেবল জানতে চান যে কাস্টিং না করা এড়াতে জেনারিকগুলি লাভ করার কোনও উপায় আছে কিনা।
ল্যাজ

2
@ ল্যাজ: হ্যাঁ, মূল প্রশ্নটি যেমন উত্থাপিত হয়েছে - টাইপ সুরক্ষা সম্পর্কিত নয়। শ্রেণি castালাই ব্যর্থতা দূর করে, এটি বাস্তবায়নের জন্য একটি নিরাপদ উপায় আছে তা সত্য পরিবর্তন করে না। এছাড়াও ওয়েবলগস.এএসপি.এন.এল.এক্সএক্স.প্যাপাদিমুলিস
ডেভিড স্মিট

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

114

আপনি এটি এভাবে প্রয়োগ করতে পারেন:

@SuppressWarnings("unchecked")
public <T extends Animal> T callFriend(String name) {
    return (T)friends.get(name);
}

(হ্যাঁ, এটি আইনী কোড; জাভা জেনারিক্স দেখুন: জেনেরিক টাইপটি কেবল রিটার্নের ধরণ হিসাবে সংজ্ঞায়িত করা হয় ))

রিটার্নের ধরণটি কলারের কাছ থেকে অনুমান করা হবে। তবে, টীকাটি নোট করুন @SuppressWarnings: এটি আপনাকে বলে যে এই কোডটি টাইপসেফ নয় । আপনাকে এটি নিজেই যাচাই করতে হবে, বা ClassCastExceptionsরানটাইম এ আপনি পেতে পারেন ।

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

jerry.<Dog>callFriend("spike").bark();

যদিও এটি কাস্টিংয়ের চেয়ে কিছুটা সুন্দর হতে পারে , তবে ডেভিড স্মিট বলেছিলেন , আপনি সম্ভবত Animalক্লাসটিকে একটি বিমূর্ত talk()পদ্ধতি দেওয়া থেকে ভাল ।


পদ্ধতি শৃঙ্খলা সত্যিই একটি উদ্দেশ্য ছিল না। সাব-টাইপ ভেরিয়েবলের মান নির্ধারণ এবং এটি ব্যবহার করতে আমার আপত্তি নেই। সমাধানের জন্য ধন্যবাদ।
সতীশ

পদ্ধতি কল চেইনিং করার সময় এটি পুরোপুরি কাজ করে!
হার্টমুট পি।

আমি সত্যিই এই সিনট্যাক্স পছন্দ। আমি সি # তে এটি jerry.CallFriend<Dog>(...মনে করি যা এটি আরও ভাল দেখাচ্ছে।
andho

মজার বিষয় হল যে java.util.Collections.emptyList()জেআরইয়ের নিজস্ব ফাংশনটি ঠিক ঠিক এর মতোই প্রয়োগ করা হয়েছে এবং এর জাভাদোক নিজেকে টাইপসেফ হিসাবে বিজ্ঞাপন দেয়।
তি স্টারগা

31

এই প্রশ্নটি কার্যকর জাভাতে আইটেম 29 এর সাথে খুব মিল - "টাইপসেফ ভিন্ন ভিন্ন ধারক বিবেচনা করুন।" ল্যাজের উত্তর হ'ল ব্লচের সমাধানের সবচেয়ে কাছের। তবে, সুরক্ষার জন্য ক্লাস আক্ষরিক ব্যবহার করা এবং করা উভয়ই উচিত। স্বাক্ষরগুলি হয়ে উঠবে:

public <T extends Animal> void addFriend(String name, Class<T> type, T animal);
public <T extends Animal> T callFriend(String name, Class<T> type);

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


17

অতিরিক্তভাবে আপনি এই পদ্ধতিতে কোনও নির্দিষ্ট ধরণের মানটি ফেরত দিতে বলতে পারেন

<T> T methodName(Class<T> var);

আরও উদাহরণ এখানে ওরাকল জাভা ডকুমেন্টেশনে


17

এখানে সহজ সংস্করণ:

public <T> T callFriend(String name) {
    return (T) friends.get(name); //Casting to T not needed in this case but its a good practice to do
}

সম্পূর্ণ কার্যকারী কোড:

    public class Test {
        public static class Animal {
            private Map<String,Animal> friends = new HashMap<>();

            public void addFriend(String name, Animal animal){
                friends.put(name,animal);
            }

            public <T> T callFriend(String name){
                return (T) friends.get(name);
            }
        }

        public static class Dog extends Animal {

            public void bark() {
                System.out.println("i am dog");
            }
        }

        public static class Duck extends Animal {

            public void quack() {
                System.out.println("i am duck");
            }
        }

        public static void main(String [] args) {
            Animal animals = new Animal();
            animals.addFriend("dog", new Dog());
            animals.addFriend("duck", new Duck());

            Dog dog = animals.callFriend("dog");
            dog.bark();

            Duck duck = animals.callFriend("duck");
            duck.quack();

        }
    }

1
কি করে Casting to T not needed in this case but it's a good practice to do। মানে রানটাইমের সময় যদি এটি সঠিকভাবে যত্ন নেওয়া হয় তবে "ভাল অনুশীলন" এর অর্থ কী?
ফরিদ

আমি বলতে চাইছিলাম সুস্পষ্ট কাস্টিং (টি) প্রয়োজন নেই যেহেতু রিটার্নের ধরণের ঘোষণার <T> পদ্ধতিতে ঘোষণাপত্রের পর্যাপ্ত পরিমাণ হওয়া উচিত
ওয়েবজকি

9

আপনি যেমন বলেছিলেন যে কোনও ক্লাস পাস করা ঠিক হবে, আপনি এটি লিখতে পারেন:

public <T extends Animal> T callFriend(String name, Class<T> clazz) {
   return (T) friends.get(name);
}

এবং তারপরে এটি ব্যবহার করুন:

jerry.callFriend("spike", Dog.class).bark();
jerry.callFriend("quacker", Duck.class).quack();

নিখুঁত নয়, তবে জাভা জেনেরিকগুলির সাথে এটি যতটা পাবেন pretty সুপার টাইপ টোকেন ব্যবহার করে টাইপসেফ হেটেরোজেনাস কনটেইনার (টিএইচসি) প্রয়োগ করার একটি উপায় রয়েছে তবে এর আবার নিজস্ব সমস্যা রয়েছে।


আমি দুঃখিত তবে ল্যাজের ঠিক উত্তরটি হ'ল তাই আপনি হয় তাকে অনুলিপি করছেন বা তিনি আপনাকে অনুলিপি করছেন।
জেমস ম্যাকমোহন

প্রকারটি পাস করার জন্য একটি ঝরঝরে উপায়। তবে তবুও এটি স্মিটের মতো নিরাপদ নয়। আমি এখনও একটি আলাদা ক্লাস পাস করতে পারলাম এবং টাইপকাস্টিং বোমা ফেলবে। টাইপ ইন রিটার্ন টাইপ সেট করতে এমএমইয়ার্স ২ য় জবাব আরও ভাল বলে মনে হচ্ছে
সতীশ

4
নেমো, আপনি যদি পোস্টের সময়টি পরীক্ষা করেন তবে আপনি দেখতে পাবেন যে আমরা একই মুহুর্তে তাদের ঠিক পোস্ট করেছি। এছাড়াও, তারা ঠিক একই নয়, কেবল দুটি লাইন।
ফ্যাবিয়ান স্টেগ

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

8

সুপার টাইপ টোকেনের মতো একই ধারণার ভিত্তিতে, আপনি স্ট্রিংয়ের পরিবর্তে টাইপ করা আইডি তৈরি করতে পারেন:

public abstract class TypedID<T extends Animal> {
  public final Type type;
  public final String id;

  protected TypedID(String id) {
    this.id = id;
    Type superclass = getClass().getGenericSuperclass();
    if (superclass instanceof Class) {
      throw new RuntimeException("Missing type parameter.");
    }
    this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
  }
}

তবে আমি মনে করি এটি উদ্দেশ্যকে পরাস্ত করতে পারে, যেহেতু আপনাকে এখন প্রতিটি স্ট্রিংয়ের জন্য নতুন আইডি অবজেক্ট তৈরি করতে হবে এবং তাদের ধরে রাখতে হবে (বা সঠিক ধরণের তথ্য দিয়ে তাদের পুনর্গঠন করতে হবে)।

Mouse jerry = new Mouse();
TypedID<Dog> spike = new TypedID<Dog>("spike") {};
TypedID<Duck> quacker = new TypedID<Duck>("quacker") {};

jerry.addFriend(spike, new Dog());
jerry.addFriend(quacker, new Duck());

তবে আপনি এখন বর্গ ছাড়াই ক্লাসটি আপনি যেমনটি চেয়েছিলেন সেভাবে ব্যবহার করতে পারেন।

jerry.callFriend(spike).bark();
jerry.callFriend(quacker).quack();

এটি কেবল আইডির ভিতরে টাইপ প্যারামিটারটি লুকিয়ে রাখছে, যদিও এর অর্থ এই নয় যে আপনি যদি চান তবে পরে শনাক্তকারী থেকে টাইপটি পুনরুদ্ধার করতে পারেন।

আপনি যদি কোনও আইডির দুটি অভিন্ন দৃষ্টান্ত তুলনা করতে সক্ষম হতে চান তবে আপনাকে টাইপডআইডি এর তুলনা এবং হ্যাশিং পদ্ধতিগুলিও কার্যকর করতে হবে।


8

"উদাহরণস্বরূপ অতিরিক্ত প্যারামিটার ব্যবহার না করে রানটাইমে রিটার্নের ধরণটি বের করার কোনও উপায় আছে কি?"

বিকল্প সমাধান হিসাবে আপনি এর মতো ভিজিটর প্যাটার্নটি ব্যবহার করতে পারেন। প্রাণীর বিমূর্ততা তৈরি করুন এবং এটি দৃশ্যমান:

abstract public class Animal implements Visitable {
  private Map<String,Animal> friends = new HashMap<String,Animal>();

  public void addFriend(String name, Animal animal){
      friends.put(name,animal);
  }

  public Animal callFriend(String name){
      return friends.get(name);
  }
}

দৃশ্যমান হ'ল অর্থ একটি প্রাণী বাস্তবায়ন একটি দর্শনার্থী গ্রহণ করতে ইচ্ছুক:

public interface Visitable {
    void accept(Visitor v);
}

এবং একটি দর্শনার্থী বাস্তবায়ন একটি প্রাণীর সমস্ত উপশ্রেণীতে যেতে সক্ষম:

public interface Visitor {
    void visit(Dog d);
    void visit(Duck d);
    void visit(Mouse m);
}

সুতরাং উদাহরণস্বরূপ একটি কুকুর বাস্তবায়ন এর পরে দেখতে হবে:

public class Dog extends Animal {
    public void bark() {}

    @Override
    public void accept(Visitor v) { v.visit(this); }
}

এখানে কৌশলটি হ'ল কুকুরটি এটি কী ধরণের তা জানে কারণ এটি "এটি" পরামিতি হিসাবে পাস করে দর্শকের v প্রাসঙ্গিক ওভারলোডেড ভিজিট পদ্ধতিটি ট্রিগার করতে পারে। অন্যান্য সাবক্লাসগুলি গ্রহণযোগ্য () ঠিক একইভাবে প্রয়োগ করবে।

যে শ্রেণীর সাবক্লাস নির্দিষ্ট পদ্ধতিগুলি কল করতে চান তাদের অবশ্যই এইভাবে ভিজিটর ইন্টারফেসটি প্রয়োগ করতে হবে:

public class Example implements Visitor {

    public void main() {
        Mouse jerry = new Mouse();
        jerry.addFriend("spike", new Dog());
        jerry.addFriend("quacker", new Duck());

        // Used to be: ((Dog) jerry.callFriend("spike")).bark();
        jerry.callFriend("spike").accept(this);

        // Used to be: ((Duck) jerry.callFriend("quacker")).quack();
        jerry.callFriend("quacker").accept(this);
    }

    // This would fire on callFriend("spike").accept(this)
    @Override
    public void visit(Dog d) { d.bark(); }

    // This would fire on callFriend("quacker").accept(this)
    @Override
    public void visit(Duck d) { d.quack(); }

    @Override
    public void visit(Mouse m) { m.squeak(); }
}

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


6

সম্ভব না. মানচিত্রটি কীভাবে জানবে যে এটি একটি স্ট্রিং কী প্রদান করে, এটি প্রাণীটির কোন সাবক্লাস পাচ্ছে?

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


5

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

  • TimeSeries<Double> ব্যবহার করে এমন একটি ব্যক্তিগত অভ্যন্তর শ্রেণীর প্রতিনিধি double[]
  • TimeSeries<OHLC> ব্যবহার করে এমন একটি ব্যক্তিগত অভ্যন্তর শ্রেণীর প্রতিনিধি ArrayList<OHLC>

দেখুন: জেনেরিক পরামিতিগুলি পুনরুদ্ধার করতে টাইপটোকেন ব্যবহার করা

ধন্যবাদ

রিচার্ড গোমেস - ব্লগ


প্রকৃতপক্ষে, আপনার অন্তর্দৃষ্টি ভাগ করে নেওয়ার জন্য আপনাকে ধন্যবাদ, আপনার নিবন্ধটি এটি সমস্ত কিছু ব্যাখ্যা করে!
ইয়ান-গাল গুহানিয়ুক

3

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

public <T extends MobilePage> T tapSignInButton(Class<T> type) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    //signInButton.click();
    return type.getConstructor(AppiumDriver.class).newInstance(appiumDriver);
}
  • মোবাইলপেজ হ'ল সুপার ক্লাস যা প্রকারটি প্রসারিত করে যার অর্থ আপনি তার শিশুদের যে কোনওটিকে ব্যবহার করতে পারেন (ডু)
  • type.getConstructor (Param.class, ইত্যাদি) আপনাকে টাইপের নির্মাণকারীর সাথে ইন্টারঅ্যাক্ট করতে দেয়। এই কনস্ট্রাক্টরটি সমস্ত প্রত্যাশিত শ্রেণীর মধ্যে একই হওয়া উচিত।
  • newInstance একটি ঘোষিত ভেরিয়েবল নেয় যা আপনি নতুন অবজেক্ট কনস্ট্রাক্টরকে দিতে চান

আপনি যদি ত্রুটিগুলি নিক্ষেপ করতে না চান তবে আপনি সেগুলি এ জাতীয়ভাবে ধরতে পারেন:

public <T extends MobilePage> T tapSignInButton(Class<T> type) {
    // signInButton.click();
    T returnValue = null;
    try {
       returnValue = type.getConstructor(AppiumDriver.class).newInstance(appiumDriver);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return returnValue;
}

আমার বোঝার জন্য, জেনারিকগুলি ব্যবহার করার এটি সেরা এবং সর্বাধিক মার্জিত উপায়।
সিব্লদান

2

সত্যিই নয়, কারণ আপনি যেমনটি বলেছেন, সংকলকটি কেবলমাত্র কলফ্রেন্ডকেই জানে যে কুকুর বা হাঁসকে নয়, একটি প্রাণী ফিরিয়ে দিচ্ছে।

আপনি কি প্রাণীর সাথে একটি বিমূর্ত MakeNoise () পদ্ধতি যুক্ত করতে পারবেন না যা এর সাবক্লাস দ্বারা ছাল বা কোয়াক হিসাবে প্রয়োগ করা হবে?


1
যদি প্রাণীদের একাধিক পদ্ধতি থাকে যা এমনকি একটি সাধারণ ক্রিয়াকলাপের আওতায় পড়ে না যা বিমূর্ত হতে পারে? আমার বিভিন্ন উপক্রমের সাথে বিভিন্ন ক্রিয়াকলাপের মধ্যে যোগাযোগের প্রয়োজন যেখানে টাইপটি পাস করার সাথে ঠিক আছে, উদাহরণ নয়।
সতীশ

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

2

আপনি এখানে যা খুঁজছেন তা বিমূর্ততা। ইন্টারফেসের বিরুদ্ধে কোড বেশি এবং আপনার কম কাস্টিং করা উচিত।

নীচের উদাহরণটি সি # তে রয়েছে তবে ধারণাটি একই রয়েছে।

using System;
using System.Collections.Generic;
using System.Reflection;

namespace GenericsTest
{
class MainClass
{
    public static void Main (string[] args)
    {
        _HasFriends jerry = new Mouse();
        jerry.AddFriend("spike", new Dog());
        jerry.AddFriend("quacker", new Duck());

        jerry.CallFriend<_Animal>("spike").Speak();
        jerry.CallFriend<_Animal>("quacker").Speak();
    }
}

interface _HasFriends
{
    void AddFriend(string name, _Animal animal);

    T CallFriend<T>(string name) where T : _Animal;
}

interface _Animal
{
    void Speak();
}

abstract class AnimalBase : _Animal, _HasFriends
{
    private Dictionary<string, _Animal> friends = new Dictionary<string, _Animal>();


    public abstract void Speak();

    public void AddFriend(string name, _Animal animal)
    {
        friends.Add(name, animal);
    }   

    public T CallFriend<T>(string name) where T : _Animal
    {
        return (T) friends[name];
    }
}

class Mouse : AnimalBase
{
    public override void Speak() { Squeek(); }

    private void Squeek()
    {
        Console.WriteLine ("Squeek! Squeek!");
    }
}

class Dog : AnimalBase
{
    public override void Speak() { Bark(); }

    private void Bark()
    {
        Console.WriteLine ("Woof!");
    }
}

class Duck : AnimalBase
{
    public override void Speak() { Quack(); }

    private void Quack()
    {
        Console.WriteLine ("Quack! Quack!");
    }
}
}

এই প্রশ্নের কোডিং নয় ধারণার সাথে সম্পর্কিত।

2

আমি আমার লাইব কনট্রাক্টরে নিম্নলিখিতগুলি করেছি:

public class Actor<SELF extends Actor> {
    public SELF self() { return (SELF)_self; }
}

subclassing:

public class MyHttpAppSession extends Actor<MyHttpAppSession> {
   ...
}

কমপক্ষে এটি বর্তমান শ্রেণীর অভ্যন্তরে এবং শক্ত টাইপযুক্ত রেফারেন্সের সাথে কাজ করে। একাধিক উত্তরাধিকার কাজ করে তবে সত্যিই কৃপণ হয়ে ওঠে :)


1

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

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

abstract class AnimalExample {
    private Map<String,Class<?>> friends = new HashMap<String,Class<?>>();
    private Map<String,Object> theFriends = new HashMap<String,Object>();

    public void addFriend(String name, Object friend){
        friends.put(name,friend.getClass());
        theFriends.put(name, friend);
    }

    public void makeMyFriendSpeak(String name){
        try {
            friends.get(name).getMethod("speak").invoke(theFriends.get(name));
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    } 

    public abstract void speak ();
};

class Dog extends Animal {
    public void speak () {
        System.out.println("woof!");
    }
}

class Duck extends Animal {
    public void speak () {
        System.out.println("quack!");
    }
}

class Cat extends Animal {
    public void speak () {
        System.out.println("miauu!");
    }
}

public class AnimalExample {

    public static void main (String [] args) {

        Cat felix = new Cat ();
        felix.addFriend("Spike", new Dog());
        felix.addFriend("Donald", new Duck());
        felix.makeMyFriendSpeak("Spike");
        felix.makeMyFriendSpeak("Donald");

    }

}

1

কি সম্পর্কে

public class Animal {
private Map<String,<T extends Animal>> friends = new HashMap<String,<T extends Animal>>();

public <T extends Animal> void addFriend(String name, T animal){
    friends.put(name,animal);
}

public <T extends Animal> T callFriend(String name){
    return friends.get(name);
}

}


0

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


আপনি "রিটার্নের ধরণের সংকীর্ণ" বলতে কী বুঝছেন তা আমি নিশ্চিত নই। আফাইক, জাভা এবং সর্বাধিক টাইপ করা ভাষাগুলি রিটার্নের ধরণের ভিত্তিতে ওভারলোড পদ্ধতি বা ফাংশন দেয় না। উদাহরণস্বরূপ সংকলক দৃষ্টিকোণ থেকে public int getValue(String name){}পৃথক পৃথক public boolean getValue(String name){}। ওভারলোডকে স্বীকৃতি দেওয়ার জন্য আপনাকে প্যারামিটারের ধরনটি পরিবর্তন করতে হবে বা পরামিতিগুলি যুক্ত / অপসারণ করতে হবে। যদিও আমি আপনাকে কেবল ভুল বোঝাবুঝি করছি ...
দ্য ট্রু কল্টার

জাভাতে আপনি একটি সাবক্লাসে একটি পদ্ধতি ওভাররাইড করতে পারেন এবং আরও "সংকীর্ণ" (অর্থাত্ আরও নির্দিষ্ট) রিটার্ন টাইপ নির্দিষ্ট করতে পারেন। স্ট্যাকওভারফ্লো . com/ প্রশ্নগুলি / 14694852/ … দেখুন ।
ফেরাল হুইপেট

-3
public <X,Y> X nextRow(Y cursor) {
    return (X) getRow(cursor);
}

private <T> Person getRow(T cursor) {
    Cursor c = (Cursor) cursor;
    Person s = null;
    if (!c.moveToNext()) {
        c.close();
    } else {
        String id = c.getString(c.getColumnIndex("id"));
        String name = c.getString(c.getColumnIndex("name"));
        s = new Person();
        s.setId(id);
        s.setName(name);
    }
    return s;
}

আপনি যে কোনও প্রকার ফিরে আসতে পারেন এবং সরাসরি পছন্দ মতো গ্রহণ করতে পারেন। টাইপকাস্ট করার দরকার নেই।

Person p = nextRow(cursor); // cursor is real database cursor.

আপনি যদি সত্যিকারের কার্সারের পরিবর্তে অন্য কোনও ধরণের রেকর্ড কাস্টমাইজ করতে চান তবে এটি সেরা।


2
আপনি বলছেন যে "টাইপকাস্ট করার দরকার নেই", তবে স্পষ্টতই সেখানে টাইপকাস্টিং জড়িত রয়েছে: (Cursor) cursorউদাহরণস্বরূপ।
সামি লাইন

এটি জেনেরিকগুলির একটি সম্পূর্ণ অনুপযুক্ত ব্যবহার। এই কোডটি cursorএকটি হতে Cursorহবে এবং সর্বদা একটি Person(বা নাল) ফিরে আসবে । জেনেরিক ব্যবহার করে কোডটি অনিরাপদ করে এই সীমাবদ্ধতাগুলির চেকিং সরিয়ে দেয়।
অ্যান্ডি টার্নার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.