java - কশন - বাংলায় জাভা pdf




কিভাবে জেনেরিক টাইপ T একটি ক্লাস উদাহরণ পেতে (12)

আমার একটি জেনেরিক ক্লাস আছে, Foo<T>Foo একটি পদ্ধতিতে, আমি টাইপের ক্লাস উদাহরণটি পেতে চাই, তবে আমি T.class কল করতে পারি না।

T.class ব্যবহার করে এটি প্রায় পেতে পছন্দের উপায় কি?


অন্য উত্তরগুলিতে ব্যাখ্যা করা হয়েছে, এই ParameterizedType পদ্ধতির ব্যবহার করার জন্য, আপনাকে বর্গটি সম্প্রসারিত করতে হবে, তবে এটি এমন একটি সম্পূর্ণ নতুন ক্লাস তৈরির মতো অতিরিক্ত কাজ মনে হচ্ছে যা এটি প্রসারিত করে ...

সুতরাং, শ্রেণী বিমূর্ত তৈরি করে এটি আপনাকে এটি প্রসারিত করতে বাধ্য করে, এইভাবে সাবক্লাসিংয়ের প্রয়োজনীয়তাকে সন্তুষ্ট করে। (লোমোককের @ গেট্টার ব্যবহার করে)।

@Getter
public abstract class ConfigurationDefinition<T> {

    private Class<T> type;
    ...

    public ConfigurationDefinition(...) {
        this.type = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        ...
    }
}

এখন একটি নতুন বর্গ সংজ্ঞায়িত ছাড়া এটি প্রসারিত। (শেষ পর্যন্ত {} নোট করুন ... বর্ধিত, কিন্তু কিছু মুছে ফেলবেন না - যতক্ষণ না আপনি চান)।

private ConfigurationDefinition<String> myConfigA = new ConfigurationDefinition<String>(...){};
private ConfigurationDefinition<File> myConfigB = new ConfigurationDefinition<File>(...){};
...
Class stringType = myConfigA.getType();
Class fileType = myConfigB.getType();

আপনি জেনারিক যে একটি বিমূর্ত superclass আছে কল্পনা করুন:

public abstract class Foo<? extends T> {}

এবং তারপরে আপনার একটি দ্বিতীয় শ্রেণী রয়েছে যা Foo কে জেনারিক বার দিয়ে প্রসারিত করে যা T:

public class Second extends Foo<Bar> {}

আপনি Type (বার্ট ব্রুনিয়োগে উত্তর থেকে) নির্বাচন করে এবং Class ইনস্ট্যান্স ব্যবহার করে এটির সাহায্যে Foo ক্লাসে ক্লাস Bar.class পেতে পারেন:

Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
//Parse it as String
String className = tType.toString().split(" ")[1];
Class clazz = Class.forName(className);

আপনি এই অপারেশনটি আদর্শ নয় তা মনে রাখবেন, তাই এটিতে একাধিক গণনা এড়ানোর জন্য গণিত মানটি ক্যাশে করা একটি ভাল ধারণা। সাধারণ ব্যবহারের একটি জেনারিক DAO বাস্তবায়ন হয়।

চূড়ান্ত বাস্তবায়ন:

public abstract class Foo<T> {

    private Class<T> inferedClass;

    public Class<T> getGenericClass(){
        if(inferedClass == null){
            Type mySuperclass = getClass().getGenericSuperclass();
            Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
            String className = tType.toString().split(" ")[1];
            inferedClass = Class.forName(className);
        }
        return inferedClass;
    }
}

ফাংশন থেকে বার বা ক্লাস থেকে Foo ক্লাস থেকে আহ্বান করা হয় যখন Bar.class ফিরে মান।



আমার এই সমস্যার জন্য একটি (কুৎসিত কিন্তু কার্যকর) সমাধান রয়েছে, যা আমি সম্প্রতি ব্যবহার করেছি:

import java.lang.reflect.TypeVariable;


public static <T> Class<T> getGenericClass()
{
    __<T> ins = new __<T>();
    TypeVariable<?>[] cls = ins.getClass().getTypeParameters(); 

    return (Class<T>)cls[0].getClass();
}

private final class __<T> // generic helper class which does only provide type information
{
    private __()
    {
    }
}

আমি একটি বিমূর্ত জেনেরিক ক্লাস এই সমস্যা ছিল। এই বিশেষ ক্ষেত্রে, সমাধানটি সহজ:

abstract class Foo<T> {
    abstract Class<T> getTClass();
    //...
}

এবং পরে প্রাপ্ত শ্রেণীর উপর:

class Bar extends Foo<Whatever> {
    @Override
    Class<T> getTClass() {
        return Whatever.class;
    }
}

আমি ক্লাসপথ উপর অতিরিক্ত নির্ভরতা যোগ ছাড়া এই কাজ করার জন্য একটি উপায় খুঁজছেন ছিল। কিছু তদন্তের পর আমি দেখেছি যে যতক্ষণ আপনি জেনেরিক সুপারটিপাইপ করেন। এটি আমার জন্য ঠিক ছিল কারণ আমি একটি জেনারিক লেয়ার সুপারটিপের সাথে একটি DAO স্তর দিয়ে কাজ করছিলাম। এটি আপনার দৃশ্যকল্প ফিট করে তবে এটি সবচেয়ে সুন্দর পদ্ধতি IMHO।

বেশিরভাগ জেনারিক্স আমি যেসব ক্ষেত্রে আসি তা ব্যবহার করে জেনারিক সুপারটিপ্যাপে কিছু ধরণের জেনারিক সুপারটি টাইপ আছে যেমন List<T> অ্যারিস্টস্টের জন্য ArrayList<T> বা GenericDAO<T> DAO<T> ইত্যাদির তালিকা।

বিশুদ্ধ জাভা সমাধান

নিবন্ধ জাভাতে রানটাইম এ জেনেরিক প্রকারের অ্যাক্সেস করে আপনি কিভাবে বিশুদ্ধ জাভা ব্যবহার করে এটি করতে পারেন তা ব্যাখ্যা করে।

বসন্ত সমাধান

আমার প্রকল্প Spring ব্যবহার করে যা স্প্রিংটি টাইপ করার জন্য একটি কার্যকর ইউটিলিটি পদ্ধতি হিসাবে আরও ভাল। এটা সবচেয়ে সুন্দর দেখায় হিসাবে এটি আমার জন্য সবচেয়ে ভাল পদ্ধতি। আমি স্প্রিং ব্যবহার করে না যদি আপনি অনুমান আপনার নিজস্ব ইউটিলিটি পদ্ধতি লিখতে পারে।

import org.springframework.core.GenericTypeResolver;

public abstract class AbstractHibernateDao<T extends DomainObject> implements DataAccessObject<T>
{

    @Autowired
    private SessionFactory sessionFactory;

    private final Class<T> genericType;

    private final String RECORD_COUNT_HQL;
    private final String FIND_ALL_HQL;

    @SuppressWarnings("unchecked")
    public AbstractHibernateDao()
    {
        this.genericType = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), AbstractHibernateDao.class);
        this.RECORD_COUNT_HQL = "select count(*) from " + this.genericType.getName();
        this.FIND_ALL_HQL = "from " + this.genericType.getName() + " t ";
    }

একটি স্ট্যান্ডার্ড পদ্ধতি / কার্যকারিতা / সমাধান কন্সট্রাক্টর (গুলি) তে একটি class বস্তু যোগ করা, যেমন:

 public class Foo<T> {

    private Class<T> type;
    public Foo(Class<T> type) {
      this.type = type;
    }

    public Class<T> getType() {
      return type;
    }

    public T newInstance() {
      return type.newInstance();
    }
 }

এখানে একটি কাজ সমাধান:

@SuppressWarnings("unchecked")
private Class<T> getGenericTypeClass() {
    try {
        String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
        Class<?> clazz = Class.forName(className);
        return (Class<T>) clazz;
    } catch (Exception e) {
        throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
    }
} 

নোট: শুধুমাত্র superclass হিসাবে ব্যবহার করা যেতে পারে

  1. টাইপকৃত শ্রেণির সাথে বর্ধিত করা হয়েছে ( Child extends Generic<Integer> )

অথবা

  1. বেনামী বাস্তবায়ন হিসাবে তৈরি করা হবে ( new Generic<Integer>() {}; )

ক্লাসের চেয়ে অন্য একটি ভাল রুট যা প্রস্তাব করা হয় তা এমন একটি বস্তুর মধ্যে পাস করা যা আপনি ক্লাসের সাথে যা করেছেন তা করতে পারেন, উদাহরণস্বরূপ, একটি নতুন উদাহরণ তৈরি করুন।

interface Factory<T> {
  T apply();
}

<T> void List<T> make10(Factory<T> factory) {
  List<T> result = new ArrayList<T>();
  for (int a = 0; a < 10; a++)
    result.add(factory.apply());
  return result;
}

class FooFactory<T> implements Factory<Foo<T>> {
  public Foo<T> apply() {
    return new Foo<T>();
  }
}

List<Foo<Integer>> foos = make10(new FooFactory<Integer>());

তবে ছোটখাটো ছোটখাটো সমস্যা রয়েছে: আপনি যদি আপনার Foo ক্লাসটি বিমূর্ত হিসাবে সংজ্ঞায়িত করেন। এর মানে হল আপনাকে ক্লাসটি তাত্ক্ষণিকভাবে চালু করতে হবে:

Foo<MyType> myFoo = new Foo<MyType>(){};

(শেষে ডবল ধনুর্বন্ধনী নোট করুন।)

এখন আপনি রান টাইম এ T টাইপ পুনরুদ্ধার করতে পারেন:

Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];

উল্লেখ্য, তবে mySuperclass শ্রেণীর সংজ্ঞাটির mySuperclass যা প্রকৃতপক্ষে T জন্য চূড়ান্ত mySuperclass সংজ্ঞায়িত করে।

এটি খুব মার্জিত নয়, তবে আপনাকে সিদ্ধান্ত নিতে হবে যে আপনি new Foo<MyType>(){} বা new Foo<MyType>(MyType.class); আপনার কোড।

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

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.NoSuchElementException;

/**
 * Captures and silently ignores stack exceptions upon popping.
 */
public abstract class SilentStack<E> extends ArrayDeque<E> {
  public E pop() {
    try {
      return super.pop();
    }
    catch( NoSuchElementException nsee ) {
      return create();
    }
  }

  public E create() {
    try {
      Type sooper = getClass().getGenericSuperclass();
      Type t = ((ParameterizedType)sooper).getActualTypeArguments()[ 0 ];

      return (E)(Class.forName( t.toString() ).newInstance());
    }
    catch( Exception e ) {
      return null;
    }
  }
}

তারপর:

public class Main {
    // Note the braces...
    private Deque<String> stack = new SilentStack<String>(){};

    public static void main( String args[] ) {
      // Returns a new instance of String.
      String s = stack.pop();
      System.out.printf( "s = '%s'\n", s );
    }
}

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

এটির একটি জনপ্রিয় সমাধান জেনারিক প্রকারের কন্সট্রকটারে টাইপ প্যারামিটারের Class পাস করা হয়, উদাহরণস্বরূপ

class Foo<T> {
    final Class<T> typeParameterClass;

    public Foo(Class<T> typeParameterClass) {
        this.typeParameterClass = typeParameterClass;
    }

    public void bar() {
        // you can access the typeParameterClass here and do whatever you like
    }
}

   public <T> T yourMethodSignature(Class<T> type) {

        // get some object and check the type match the given type
        Object result = ...            

        if (type.isAssignableFrom(result.getClass())) {
            return (T)result;
        } else {
            // handle the error
        }
   }




generics