জাভা: ইনস্ট্যান্সফ এবং জেনারিক্স


135

কোনও মান সূচকের জন্য আমার জেনেরিক ডেটা কাঠামোটি দেখার আগে, আমি দেখতে চাই যে এটি এমনকি কোনও ধরণের উদাহরণ thisহিসাবে প্যারামাইট্রাইজ করা হয়েছে কিনা।

তবে আমি যখন এটি করি তখন গ্রহগ্রহের অভিযোগ:

@Override
public int indexOf(Object arg0) {
    if (!(arg0 instanceof E)) {
        return -1;
    }

এটি ত্রুটি বার্তা:

টাইপ প্যারামিটার ই এর বিরুদ্ধে চেক সম্পাদন করতে পারে না instead পরিবর্তে এর ক্ষয়কারী অবজেক্টটি ব্যবহার করুন যেহেতু জেনেরিক ধরণের তথ্য রানটাইমের সময় মুছে যাবে

এটি করার ভাল উপায় কি?

উত্তর:


79

ত্রুটি বার্তাটি সব বলে। রানটাইমের সময়, টাইপটি চলে গেছে, এটির জন্য চেক করার কোনও উপায় নেই।

আপনি নিজের বস্তুর জন্য কারখানা তৈরি করে এটি ধরতে পারেন:

 public static <T> MyObject<T> createMyObject(Class<T> type) {
    return new MyObject<T>(type);
 }

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

        if (arg0 != null && !(this.type.isAssignableFrom(arg0.getClass()))
        {
            return -1;
        }

3
আমি মনে করি না আপনি চান Class.isAssignableFrom
টম হাটিন -

@ টম, আমি গত রাতে এই স্মৃতি থেকে লিখেছিলাম এবং আমি এটি ক্লাসে পাস করার জন্য ঠিক করেছি (দুহ!) তবে অন্যথায়, আপনি কেন এটি চান না তা আমি বুঝতে পারি না (সম্ভবত আজ সকালে আমার আরও কফির দরকার আছে, আমি ' আমি কেবল আমার প্রথম কাপে)।
ইশাই 13

আমি টমের সাথে আছি আপনি কি এটা পরিষ্কার করতে পারেন? IsAignignableFrom () ব্যবহার করা আমার কাজের জন্য বেছে নেওয়া হত। আমি কি কিছু মিস করছি?
luis.espinal

6
@ লুইস, টমের মন্তব্যে সম্ভবত আমার আইসনস্ট্যান্স () ব্যবহার করা উচিত এবং আসল আরগ0 প্যারামিটারটি পাস করা উচিত। এটি নাল চেক এড়ানো সুবিধা আছে।
যিশাই

1
আমারও একই অবস্থা তবে আমি উত্তরটি পুরোপুরি বুঝতে পারি না। আপনি কি দয়া করে আমার মতো ডামির পক্ষে আরও ভাল করে স্পষ্ট করে বলতে পারেন?
রুবেেন্স মারিউজো

40

জেনেরিকের সাথে রানটাইম টাইপ পরীক্ষার জন্য দুটি বিকল্প:

বিকল্প 1 - আপনার নির্মাণকারীর দুর্নীতি

ধরে নেওয়া যাক আপনি সূচক (...) কে ওভাররাইড করছেন, এবং পুরো সংগ্রহটি পুনরাবৃত্তি করে নিজেকে বাঁচাতে আপনি কেবল পারফরম্যান্সের জন্য টাইপটি পরীক্ষা করতে চান।

এই মত একটি নোংরা নির্মাণকারী করুন:

public MyCollection<T>(Class<T> t) {

    this.t = t;
}

তারপরে আপনি টাইপটি পরীক্ষা করতে isignableFrom ব্যবহার করতে পারেন ।

public int indexOf(Object o) {

    if (
        o != null &&

        !t.isAssignableFrom(o.getClass())

    ) return -1;

//...

প্রতিবার আপনি যখন নিজের অবজেক্টটি ইনস্ট্যান্ট করবেন তখন আপনাকে নিজের পুনরাবৃত্তি করতে হবে:

new MyCollection<Apples>(Apples.class);

আপনি সিদ্ধান্ত নিতে পারেন এটি উপযুক্ত নয়। অ্যারেলিস্ট.ইন্ডেক্সঅফ (...) এর বাস্তবায়নে , তারা পরীক্ষা করে না যে টাইপটি মেলে।

বিকল্প 2 - এটি ব্যর্থ হতে দিন

যদি আপনাকে এমন একটি বিমূর্ত পদ্ধতি ব্যবহার করতে হয় যার জন্য আপনার অজানা প্রকারের প্রয়োজন হয়, তবে আপনি যা চান তা হ'ল কম্পাইলারটি উদাহরণস্বরূপ কান্নাকাটি বন্ধ করে দেবে । আপনার যদি এই জাতীয় পদ্ধতি থাকে:

protected abstract void abstractMethod(T element);

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

public int indexOf(Object o) {

    try {

        abstractMethod((T) o);

    } catch (ClassCastException e) {

//...

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

দ্রষ্টব্য 1: আপনি যদি আপনার বিমূর্ত পদ্ধতিতে অতিরিক্ত চেক না করা ক্যাসেটগুলি করছেন তবে আপনার ক্লাসকাস্টএক্সেপশনগুলি এখানে ধরা পড়বে। এটি ভাল বা খারাপ হতে পারে, তাই এটির মাধ্যমে চিন্তা করুন।

দ্রষ্টব্য 2: আপনি উদাহরণ ব্যবহার করার সময় একটি নিখুঁত নাল চেক পাবেন । যেহেতু আপনি এটি ব্যবহার করতে পারবেন না, আপনার খালি হাতে নাল পরীক্ষা করার প্রয়োজন হতে পারে।


18

পুরানো পোস্ট, তবে জেনেরিক উদাহরণটি করার সহজ উপায় যাচাই করা হয়েছে।

public static <T> boolean isInstanceOf(Class<T> clazz, Class<T> targetClass) {
    return clazz.isInstance(targetClass);
}

21
আপনি এখানে যা অবদান রাখছেন তা অস্পষ্ট।
অ্যান্ড্রু

12

আপনার ক্লাসটি জেনেরিক প্যারামিটার সহ একটি ক্লাস প্রসারিত করে, আপনি এটি প্রতিফলনের মাধ্যমে রানটাইমেও পেতে পারেন এবং তারপরে তুলনা করার জন্য এটি ব্যবহার করতে পারেন, যেমন

class YourClass extends SomeOtherClass<String>
{

   private Class<?> clazz;

   public Class<?> getParameterizedClass()
   {
      if(clazz == null)
      {
         ParameterizedType pt = (ParameterizedType)this.getClass().getGenericSuperclass();
          clazz = (Class<?>)pt.getActualTypeArguments()[0];
       }
       return clazz;
    }
}

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


7

আমার একই সমস্যা ছিল এবং এটি আমার সমাধান (খুব নম্র, @ জর্জ: এই বার সংকলন এবং কাজ করছে ...)।

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

আমি কেবলমাত্র টি টাইপের অবজেক্টগুলি পরিচালনা করতে চাই

সমাধানটি রানটাইমগুলিতে ধরণের তুলনা করতে সক্ষম হওয়ার জন্য ক্লাসটি কনস্ট্রাক্টরের কাছে পাস করা।

public abstract class AbstractOne<T> implements Observer {

  private Class<T> tClass;
    public AbstractOne(Class<T> clazz) {
    tClass = clazz;
  }

  @Override
  public void update(Observable o, Object arg) {
    if (tClass.isInstance(arg)) {
      // Here I am, arg has the type T
      foo((T) arg);
    }
  }

  public abstract foo(T t);

}

বাস্তবায়নের জন্য আমাদের কেবল ক্লাসটি কনস্ট্রাক্টরে পাস করতে হবে

public class OneImpl extends AbstractOne<Rule> {
  public OneImpl() {
    super(Rule.class);
  }

  @Override
  public void foo(Rule t){
  }
}

5

অথবা আপনি E তে কাস্ট করার ব্যর্থ চেষ্টাটি ধরতে পারেন

public int indexOf(Object arg0){
  try{
    E test=(E)arg0;
    return doStuff(test);
  }catch(ClassCastException e){
    return -1;
  }
}

1
+1 একটি সাধারণ পরীক্ষার জন্য একটি বাস্তব-অ-ওভার ইঞ্জিনিয়ারড সমাধান! আমি আশা করি আমি আরও বেশি ভোট দিতে পারতাম
হিগুয়ারো

24
এটি কাজ করবে না। E রানটাইম এ মুছে ফেলা হয়েছে, তাই কাস্ট ব্যর্থ হবে না, আপনি এটি সম্পর্কে একটি কম্পাইলার সতর্কতা পাবেন।
ইশাই

1

প্রযুক্তিগতভাবে আপনার দরকার নেই, এটি জেনারিকের মূল বিষয়, যাতে আপনি কম্পাইল-টাইপ চেকিং করতে পারেন:

public int indexOf(E arg0) {
   ...
}

তবে আপনার যদি ক্লাস শ্রেণিবদ্ধতা থাকে তবে @ ওভাররাইড সমস্যা হতে পারে। নাহলে isশাইয়ের উত্তর দেখুন।


হ্যাঁ, তালিকা ইন্টারফেসের দাবি করে যে ফাংশনটি কোনও অবজেক্টের প্যারামিটার নেবে।
নিক হেইনার

আপনি তালিকা বাস্তবায়ন করছেন? আপনি তালিকা <E> প্রয়োগ করছেন না কেন?
জেসন এস

(উদাহরণস্বরূপ অ্যারেলিস্টের ঘোষণা দেখুন: java.sun.com/j2se/1.5.0/docs/api/java/util/ArrayList.html )
জেসন এস

@ রশারচ: তালিকার ইন্টারফেসের সূচিপত্র () পদ্ধতির প্রয়োজন হয় না যে প্রদত্ত যুক্তিটি আপনি যে বস্তুর সন্ধান করছেন ঠিক একই ধরণের। এটি কেবলমাত্র তার কাছে যথাযথ () হতে হবে এবং বিভিন্ন ধরণের জিনিসগুলি একে অপরের কাছে .equals () হতে পারে। এই পদ্ধতি সরান () এর জন্য হিসাবে একই বিষয়, দেখুন: stackoverflow.com/questions/104799/...
newacct

1
[[[মেষশালী]]] কিছু মনে করবেন না, আমি ভেবেছিলাম ইন্ডেক্সঅফ () এর অবজেক্টের চেয়ে প্যারামিটার হিসাবে ই প্রয়োজন। (তারা কেন এটি করেছিল?! ??!)
জেসন এস

1

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

public interface FilterObject {
     boolean isAllowed(Object obj);
}

public class FilterOptimizedList<E> implements List<E> {
     private final FilterObject filter;
     ...
     public FilterOptimizedList(FilterObject filter) {
         if (filter == null) {
             throw NullPointerException();
         }
         this.filter = filter;
     }
     ...
     public int indexOf(Object obj) {
         if (!filter.isAllows(obj)) {
              return -1;
         }
         ...
     }
     ...
}

     final List<String> longStrs = new FilterOptimizedList<String>(
         new FilterObject() { public boolean isAllowed(Object obj) {
             if (obj == null) {
                 return true;
             } else if (obj instanceof String) {
                 String str = (String)str;
                 return str.length() > = 4;
             } else {
                 return false;
             }
         }}
     );

(যদিও আপনি একটি দৃষ্টান্ত প্রকার চেক করতে আপনি ব্যবহার করছেন কিনা তা চাইতে পারেন Comparatorবা অনুরূপ।)
টম Hawtin - tackline
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.