প্রতিবিম্ব সহ জাভাতে জেনেরিক প্যারামিটারের ধরণ পান


143

জেনেরিক প্যারামিটারের ধরণটি পাওয়া কি সম্ভব?

একটি উদাহরণ:

public final class Voodoo {
    public static void chill(List<?> aListWithTypeSpiderMan) {
        // Here I'd like to get the Class-Object 'SpiderMan'
        Class typeOfTheList = ???;
    }

    public static void main(String... args) {
        chill(new ArrayList<SpiderMan>());
    }
}

উত্তর:


156

একটি কনস্ট্রাক্ট, আমি একবার দেখতে দেখতে হোঁচট খেয়েছি

Class<T> persistentClass = (Class<T>)
   ((ParameterizedType)getClass().getGenericSuperclass())
      .getActualTypeArguments()[0];

সুতরাং চারপাশে এমন কিছু প্রতিবিম্ব-যাদু আছে যা আমি দুর্ভাগ্যবশত পুরোপুরি বুঝতে পারি না ... দুঃখিত।


2
তবে এটিকে বিমূর্ত হিসাবে ঘোষণা করুন। আপনি যখন এটি ব্যবহার করতে চান, তারপরে এটি ইনলাইন সাবক্লাস করুন।
স্নিকোলাস

42
যদিও এটি খুব পুরানো এবং কোনও কারণে গৃহীত হয়েছে, তবে আমি এটিকে কমিয়ে দিয়েছি কারণ এটি কেবল প্রশ্নের উত্তর দেয় না। এটি হবে না প্রশ্নে দেওয়া উদাহরণে "স্পাইডারম্যান" দেব। এটি নিঃসন্দেহে কিছু পরিস্থিতিতে কার্যকর, তবে এটি যে প্রশ্ন জিজ্ঞাসা করেছিল তা কার্যকর করে না।
জন স্কিটি

15
এখন পর্যন্ত যারা এসেছেন কেউই উত্তরের জন্য "এটি করা যায় না" মেনে নেবেন না। আমরা মরিয়া কারণ আমরা এখানে আছি।
অ্যাডিসন

14
আমি এই ব্যতিক্রম পেয়েছি: Exception in thread "main" java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType সীমাবদ্ধতা কি তা নিশ্চিত নয়।
ডিশ

4
@ ডিশের মতো আমি কেবল একটি পেয়েছিjava.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
কেনি ওয়াইল্যান্ড

133

আমি ব্যাখ্যা করতে ডার্মাইক থেকে উত্তরটি ভেঙে দেওয়ার চেষ্টা করতে চাই:

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

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

যাইহোক, ব্যাখ্যা থেকে। এখানে কোড আবার, রেফারেন্সের স্বাচ্ছন্দ্যের জন্য লাইনে বিভক্ত:

1 # শ্রেণীর জেনেরিকপ্যারামিটার 0 আগে এই ক্লাস = 
2 # (শ্রেণি)
3 # ((প্যারামিটারাইজড টাইপ)
4 # getClass ()
5 # .সেট জেনেরিকসপারক্লাস ())
6 # .getActualTypeArguments () [0];

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

  • লাইন 4 বর্তমান কংক্রিট শ্রেণীর ক্লাস উদাহরণ পেয়েছে। এটি আমাদের তাত্ক্ষণিক বংশধরের কংক্রিটের ধরণ চিহ্নিত করে।
  • লাইন 5 সেই ধরণের ক্লাস পায় 'টাইপ হিসাবে সুপারটাইপ; এই যে আমরা. যেহেতু আমরা একটি প্যারাম্যাট্রিক টাইপ করছি আমরা নিরাপদে নিজেকে প্যারামিটারাইজড টাইপ (লাইন 3) এ কাস্ট করতে পারি। মূলটি হ'ল যখন জাভা এই ধরণের অবজেক্টটি নির্ধারণ করে, এটি নতুন প্যারামিটারাইজড টাইপের ক্ষেত্রে আমাদের টাইপ পরামিতিগুলির সাথে টাইপ তথ্য সংযুক্ত করতে বাচ্চার উপস্থিত টাইপ তথ্য ব্যবহার করে। সুতরাং এখন আমরা আমাদের জেনেরিকের জন্য কংক্রিটের ধরণের অ্যাক্সেস করতে পারি।
  • শ্রেণি কোডে ঘোষিত অনুযায়ী লাইন 6 আমাদের জেনারিকগুলিতে ম্যাপযুক্ত ধরণের অ্যারে পায়। এই উদাহরণের জন্য আমরা প্রথম প্যারামিটারটি বের করি। এটি টাইপ হিসাবে ফিরে আসে।
  • লাইন 2 চূড়ান্ত প্রকারটি একটি শ্রেণিতে ফিরে এসেছে ts এটি নিরাপদ কারণ আমরা জানি যে আমাদের জেনেরিক ধরণের পরামিতিগুলি কী ধরণের নিতে পারে এবং তা নিশ্চিত করতে পারে যে সেগুলি সমস্ত শ্রেণি হবে (আমি নিশ্চিত নই যে জাভাতে কীভাবে জেনেরিক পরামিতি পাওয়া যাবে যার ক্লাস উদাহরণ নেই) এর সাথে যুক্ত, আসলে)।

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

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

আশা করি এটি কারও সাহায্য করেছে! আমি জানি এই পোস্টটি প্রাচীন। আমি সম্ভবত এই ব্যাখ্যাটি স্নাপ করব এবং অন্যান্য প্রশ্নের জন্য রেখে দেব।


3
আপনার "কেবলমাত্র জাভাতে জেনেরিক প্যারামিটারের সাথে কোনও ক্লাস উদাহরণ যুক্ত করা যায় না সে সম্পর্কে আমি নিশ্চিত নই," আসলে: জেনেরিক ক্লাসের প্যারামিটারটি যদি হয় তবে এটি সম্ভব " ওয়াইল্ডকার্ড এক্সপ্রেশন "(বলুন:? সামার ক্লাস প্রসারিত হয়) বা" টাইপ ভেরিয়েবল "(বলুন: <T> যেখানে টি জেনেরিক সাবক্লাস থেকে আসে)। উভয় ক্ষেত্রেই "প্রকার" উদাহরণগুলি "শ্রেণিতে" কাস্ট করা যাবে না কারণ টাইপ ইন্টারফেস বাস্তবায়িত উভয়ের জন্য প্রতিটি ভিএমের পৃথক বাস্তবায়ন থাকতে পারে তবে সরাসরি java.lang.Class থেকে প্রাপ্ত হয় না।
রবার্তো অ্যান্ড্রেড

19

আসলে আমি এই কাজ পেয়েছিলাম। নিম্নলিখিত স্নিপেট বিবেচনা করুন:

Method m;
Type[] genericParameterTypes = m.getGenericParameterTypes();
for (int i = 0; i < genericParameterTypes.length; i++) {
     if( genericParameterTypes[i] instanceof ParameterizedType ) {
                Type[] parameters = ((ParameterizedType)genericParameterTypes[i]).getActualTypeArguments();
//parameters[0] contains java.lang.String for method like "method(List<String> value)"

     }
 }

আমি jdk 1.6 ব্যবহার করছি


12
-1: এটি প্রশ্নের সমস্যার সমাধান করে না; এটি কেবল পদ্ধতি স্বাক্ষরে ঘোষিত টাইপ দেয়, আসল রানটাইম টাইপ নয়।
মাইকেল বর্গওয়ার্ট

5
ওপি-র প্রশ্নের উত্তর নাও দিতে পারে, তবে এটি একটি কার্যকর কৌশল।
dnault

3
এটি সম্পূর্ণ ভিন্ন প্রশ্নের উত্তর।
দাউদ ইবনে কেরেম

সমস্ত প্রকৃত প্রকার পেতে আপনি m.getParameterType () কল করতে পারেন। উদাহরণস্বরূপ এটি "তালিকা" ফিরে আসবে।
লি মায়াদোর

জেনেরিকপ্যারামিটারটাইপস [i] যদি প্যারামিটারাইজড টাইপগুলির উদাহরণ না হয় তবে এটি একটি শ্রেণি হতে পারে। তার মানে হল যে পদ্ধতির একটি নির্দিষ্ট যুক্তি মোটেই প্যারামিটারাইজড নয়।
লি মায়াদোর

18

আসলে "বেনাম শ্রেণীর" কৌশল এবং সুপার টাইপ টোকেনের ধারণাগুলি প্রয়োগ করে একটি সমাধান রয়েছে :

public final class Voodoo {
    public static void chill(final List<?> aListWithSomeType) {
        // Here I'd like to get the Class-Object 'SpiderMan'
        System.out.println(aListWithSomeType.getClass().getGenericSuperclass());
        System.out.println(((ParameterizedType) aListWithSomeType
            .getClass()
            .getGenericSuperclass()).getActualTypeArguments()[0]);
    }
    public static void main(String... args) {
        chill(new ArrayList<SpiderMan>() {});
    }
}
class SpiderMan {
}

একটি সৃষ্টির কৌতুক মিথ্যা বেনামী বর্গ , new ArrayList<SpiderMan>() {}, মূল (সাধারণ) স্থানে new ArrayList<SpiderMan>()। অ্যানয়মাস ক্লাসের ব্যবহার (যদি সম্ভব হয়) তা নিশ্চিত করে যে সংকলক SpiderManটাইপ প্যারামিটারে প্রদত্ত টাইপ আর্গুমেন্ট সম্পর্কে তথ্য বজায় রাখে List<?>। ভয়েল!


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

এফওয়াইআই, প্রথম লিঙ্কটি মারা গেছে
আশ্বিন শর্মা

@ আশ্বিনশর্মা আমি বিশ্বাস করি যে এখানে একই উপাদান পাওয়া যায়: rgomes.info/used-typetokens-to-retrieve-generic-paraters
Yann-Gaël Guéhéneuc

7

টাইপ ইরেজরের কারণে তালিকার প্রকারটি জানার একমাত্র উপায় হ'ল পদ্ধতিতে প্যারামিটার হিসাবে টাইপটিতে পাস করা:

public class Main {

    public static void main(String[] args) {
        doStuff(new LinkedList<String>(), String.class);

    }

    public static <E> void doStuff(List<E> list, Class<E> clazz) {

    }

}

7

প্যারামিটারাইজড ইন্টারফেসের জেনেরিক প্যারামিটার পাওয়ার জন্য @ ডারমাইকের জবাবের পরিশিষ্ট ( ডুপ্লিকেশন এড়াতে জাভা -8 ডিফল্ট পদ্ধতির অভ্যন্তরে #getGenericInterfaces () পদ্ধতি ব্যবহার করে ):

import java.lang.reflect.ParameterizedType; 

public class ParametrizedStuff {

@SuppressWarnings("unchecked")
interface Awesomable<T> {
    default Class<T> parameterizedType() {
        return (Class<T>) ((ParameterizedType)
        this.getClass().getGenericInterfaces()[0])
            .getActualTypeArguments()[0];
    }
}

static class Beer {};
static class EstrellaGalicia implements Awesomable<Beer> {};

public static void main(String[] args) {
    System.out.println("Type is: " + new EstrellaGalicia().parameterizedType());
    // --> Type is: ParameterizedStuff$Beer
}

এটি মূল পোস্টটি যা চেয়েছিল তা নয়। এখানে আপনি একটি সাবক্লাস তৈরি করেছেন Awesomeable<Beer>। সেক্ষেত্রে প্রকারের তথ্য সংরক্ষণ করা হয়। আপনি যদি new Awesomable<Beer> ()পদ্ধতিতে পাস করেন wt কাজ করবে না।
ফ্লোরিয়ান এফ

@ ফ্লোরিয়ানএফ যদি আপনি এই ক্ষেত্রে Awesomable<Beer>যেমন কংক্রিটের সাবক্লাসের সুস্পষ্ট সংজ্ঞা ছাড়াই উড়ে চলে যান তবে EstrellaGaliciaএখনও এটি প্যারামিটারাইজড টাইপ থেকে বেরিয়ে আসছে: আমি এখনই এটি System.out.println("Type is: " + new Awesomable<Beer>() {}.parameterizedType());
চালিয়েছি

6

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


যদিও জাভা রানটাইমের সময় এটি মেটা ডেটা হিসাবে সঞ্চয় করতে পারে, তাই না? আমি এটা আশা করি। দুর্ভাগ্য.
সিমনাইন

1
@ ব্যবহারকারী 99475: না। আমি ঠিক আছি এবং অ্যান্ড্রেও ভুল। তিনি আমার উত্তরের দ্বিতীয় অংশে আমি যে ধরণের তথ্য উল্লেখ করেছি উল্লেখ করছি, তবে প্রশ্নটি যা তা চায় তা নয়।
মাইকেল বর্গওয়ার্ট

5

@ বার্টোলামি দ্বারা চিহ্নিত হিসাবে, এটি আমাদের পক্ষে একটি পরিবর্তনশীল প্রকারের পক্ষে সম্ভব না এবং এর ভবিষ্যতের মান (টাইপঅফলিট ভেরিয়েবলের সামগ্রী) পাওয়া সম্ভব নয়।

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

public final class voodoo {
    public static void chill(List<T> aListWithTypeSpiderMan, Class<T> clazz) {
        // Here I'd like to get the Class-Object 'SpiderMan'
        Class typeOfTheList = clazz;
    }

    public static void main(String... args) {
        chill(new List<SpiderMan>(), Spiderman.class );
    }
}

অ্যাক্টিভিটিসিনস্ট্রেশনেশন টেস্টক্যাস 2 এর কনস্ট্রাক্টরের কাছে আপনাকে যখন ক্লাস ভেরিয়েবল পাস করতে হয় তখন গুগল কমবেশি তা করে ।


3

না এটা সম্ভব নয়।

আপনি কোনও শ্রেণীর প্রদত্ত জেনেরিক ধরণের ক্ষেত্র পেতে পারেন সেই নিয়মের একমাত্র ব্যতিক্রম এবং এমনকি এটি হ্যাকও।

এর উদাহরণের জন্য জাভাতে জেনেরিকের প্রকারটি জানুন


1

আপনি এই উদাহরণে আমি দেখেছি যে মত প্রতিফলন সঙ্গে একটি জেনেরিক পরামিতি ধরণ পেতে পারেন এখানে :

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

public class Home<E> {
    @SuppressWarnings ("unchecked")
    public Class<E> getTypeParameterClass(){
        Type type = getClass().getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) type;
        return (Class<E>) paramType.getActualTypeArguments()[0];
    }

    private static class StringHome extends Home<String>{}
    private static class StringBuilderHome extends Home<StringBuilder>{}
    private static class StringBufferHome extends Home<StringBuffer>{}   

    /**
     * This prints "String", "StringBuilder" and "StringBuffer"
     */
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Object object0 = new StringHome().getTypeParameterClass().newInstance();
        Object object1 = new StringBuilderHome().getTypeParameterClass().newInstance();
        Object object2 = new StringBufferHome().getTypeParameterClass().newInstance();
        System.out.println(object0.getClass().getSimpleName());
        System.out.println(object1.getClass().getSimpleName());
        System.out.println(object2.getClass().getSimpleName());
    }
}

হোম <কে, ভি> এর ভি পেতে আপনি একই জিনিসটি কীভাবে করবেন?
রাফায়েল সান্চস

1

জাভা জেনেরিক ধরণের ইরেজরের কারণে প্রশ্নের উত্তরটির উত্তর আপনি পারবেন না।

দীর্ঘ উত্তরটি হ'ল যদি আপনি আপনার তালিকাটি এইভাবে তৈরি করেন:

new ArrayList<SpideMan>(){}

তারপরে এই ক্ষেত্রে জেনেরিক প্রকারটি উপরের নতুন বেনাম শ্রেণীর জেনেরিক সুপারক্লাসে সংরক্ষণ করা হবে।

আমি তালিকাগুলি দিয়ে এটি করার পরামর্শ দিই না, তবে এটি শ্রোতার বাস্তবায়ন:

new Listener<Type>() { public void doSomething(Type t){...}}

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

এখানে এখন আমি এটা করেছি।


0

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


হ্যাঁ আমি এখন এটিই করছি। তবে এখন তালিকাটি খালি থাকলেও আমি প্রকারটি জানতে চাই। তবে চারজন ছেলে ভুল হতে পারে না। সবাইকে ধন্যবাদ)!
সিমনাইন

19
এটি সত্য নয়। এটি জটিল হলেও আপনি পরবর্তী পোস্টে দেখতে পাবেন যে প্যারামিটারাইজডটাইপ এটি করতে দেয়।
এডমন্ডো 1984

1
সম্মত হন, এটি করা যেতে পারে। ডারমাইকের উদাহরণ এটির রূপরেখা দেয় (আমার পক্ষে কাজ করেছে)।
ম্যাক

LOL এ "চারজন লোক ভুল হতে পারে না"। এই উত্তরটি সঠিক।
দাউদ ইবনে কেরেম

0

আমি গ্রহণযোগ্য বা ফিরে প্রত্যাশা এমন পদ্ধতিগুলির জন্য এটি কোড করে রেখেছি Iterable<?...>। কোডটি এখানে:

/**
 * Assuming the given method returns or takes an Iterable<T>, this determines the type T.
 * T may or may not extend WindupVertexFrame.
 */
private static Class typeOfIterable(Method method, boolean setter)
{
    Type type;
    if (setter) {
        Type[] types = method.getGenericParameterTypes();
        // The first parameter to the method expected to be Iterable<...> .
        if (types.length == 0)
            throw new IllegalArgumentException("Given method has 0 params: " + method);
        type = types[0];
    }
    else {
        type = method.getGenericReturnType();
    }

    // Now get the parametrized type of the generic.
    if (!(type instanceof ParameterizedType))
        throw new IllegalArgumentException("Given method's 1st param type is not parametrized generic: " + method);
    ParameterizedType pType = (ParameterizedType) type;
    final Type[] actualArgs = pType.getActualTypeArguments();
    if (actualArgs.length == 0)
        throw new IllegalArgumentException("Given method's 1st param type is not parametrized generic: " + method);

    Type t = actualArgs[0];
    if (t instanceof Class)
        return (Class<?>) t;

    if (t instanceof TypeVariable){
        TypeVariable tv =  (TypeVariable) actualArgs[0];
        AnnotatedType[] annotatedBounds = tv.getAnnotatedBounds();///
        GenericDeclaration genericDeclaration = tv.getGenericDeclaration();///
        return (Class) tv.getAnnotatedBounds()[0].getType();
    }

    throw new IllegalArgumentException("Unknown kind of type: " + t.getTypeName());
}

0

আপনি একটি ভেরিয়েবল থেকে জেনেরিক প্যারামিটার পেতে পারেন না। তবে আপনি কোনও পদ্ধতি বা ক্ষেত্রের ঘোষণা থেকে:

Method method = getClass().getDeclaredMethod("chill", List.class);
Type[] params = method.getGenericParameterTypes();
ParameterizedType firstParam = (ParameterizedType) params[0];
Type[] paramsOfFirstGeneric = firstParam.getActualTypeArguments();

এটি আমাকে থ্রেডে "মেইন" জাভা.লং.ক্লাসকাস্টএক্সেপশন: এক্সপ্লোরেশন.জেনারিক্স.প্রিলিটিভঅবজেক্টস। টাইপ ভেরিয়েবলআইপল
মার্টিনেজ

'প্যারামস' হ'ল টাইপ যার বেশ কয়েকটি সাব-ইন্টারফেস রয়েছে। TypeVariableImpl হ'ল এক যে পদ্ধতি আর্গুমেন্টের জন্য ব্যবহৃত হয় এবং এটি <> s এর মধ্যে জেনেরিকের নাম বলে, এটি যে শ্রেণীর প্রতিনিধিত্ব করে তা নয়।
লি মায়াদোর

0

কোডের এই স্নিপেটটি কেবল আমার পক্ষে পড়া শক্ত ছিল, আমি কেবল এটি 2 পঠনযোগ্য লাইনে বিভক্ত করেছি:

// assuming that the Generic Type parameter is of type "T"
ParameterizedType p = (ParameterizedType) getClass().getGenericSuperclass();
Class<T> c =(Class<T>)p.getActualTypeArguments()[0];

আমি আমার পদ্ধতির কোনও পরামিতি ছাড়াই টাইপ প্যারামিটারের একটি উদাহরণ তৈরি করতে চেয়েছিলাম:

publc T getNewTypeInstance(){
    ParameterizedType p = (ParameterizedType) getClass().getGenericSuperclass();
    Class<T> c =(Class<T>)p.getActualTypeArguments()[0];

    // for me i wanted to get the type to create an instance
    // from the no-args default constructor
    T t = null;
    try{
        t = c.newInstance();
    }catch(Exception e){
        // no default constructor available
    }
    return t;
}

0

এখানে অন্য কৌশল। জেনেরিক ভারার্গ অ্যারে ব্যবহার করুন

import java.util.ArrayList;

class TypedArrayList<E> extends ArrayList<E>
{
    @SafeVarargs
    public TypedArrayList (E... typeInfo)
    {
        // Get generic type at runtime ...
        System.out.println (typeInfo.getClass().getComponentType().getTypeName());
    }
}

public class GenericTest
{
    public static void main (String[] args)
    {
        // No need to supply the dummy argument
        ArrayList<Integer> ar1 = new TypedArrayList<> ();
        ArrayList<String> ar2 = new TypedArrayList<> ();
        ArrayList<?> ar3 = new TypedArrayList<> ();
    }
}

0

আমি লক্ষ্য করেছি যে অনেকে getGenericSuperclass()সমাধানের দিকে ঝুঁকছেন:

class RootGeneric<T> {
  public Class<T> persistentClass = (Class<T>)
    ((ParameterizedType)getClass().getGenericSuperclass())
      .getActualTypeArguments()[0];
}

তবে এই সমাধানটি ত্রুটিযুক্ত one বংশধরদের মধ্যে জেনেরিক থাকলে এটি সঠিকভাবে কাজ করবে না । এই বিবেচনা:

class Foo<S> extends RootGeneric<Integer> {}

class Bar extends Foo<Double> {}

কোন ধরণের Bar.persistentClassথাকবে? Class<Integer>? নাহ, এটা হবে Class<Double>। এটি getClass()সর্বদা সর্বাধিক শ্রেণীর ফিরিয়ে দেওয়ার কারণে ঘটবে , যা Barএই ক্ষেত্রে, এবং এর জেনেরিক সুপার ক্লাসFoo<Double> । সুতরাং, যুক্তির ধরণটি হবেDouble

আপনার যদি নির্ভরযোগ্য সমাধানের প্রয়োজন হয় যা ব্যর্থ হয় না তবে আমি দুটি পরামর্শ দিতে পারি।

  1. ব্যবহার Guava। এটা একটা শ্রেণী যে এই কাজের জন্য ঠিক করা হয় আছে: com.google.common.reflect.TypeToken। এটি কোণার সমস্ত কেস ঠিকঠাক পরিচালনা করে এবং আরও কিছু দুর্দান্ত কার্যকারিতা সরবরাহ করে। ডাউনসাইড একটি অতিরিক্ত নির্ভরতা। আপনি এই শ্রেণিটি ব্যবহার করেছেন, আপনার কোডটি সহজ এবং পরিষ্কার দেখাবে, এর মতো:
class RootGeneric<T> {
  @SuppressWarnings("unchecked")
  public final Class<T> persistentClass = (Class<T>) (new TypeToken<T>(getClass()) {}.getType());
}
  1. নীচে কাস্টম পদ্ধতি ব্যবহার করুন। এটি উপরে উল্লিখিত পেয়ারা শ্রেণীর অনুরূপ একটি উল্লেখযোগ্য সরল যুক্তি প্রয়োগ করে। তবে, আমি এটির ত্রুটিযুক্ত গ্যারান্টি দিচ্ছি না। এটি যদিও জেনেরিক বংশধরদের সাথে সমস্যাটি সমাধান করে।
abstract class RootGeneric<T> {
  @SuppressWarnings("unchecked")
  private Class<T> getTypeOfT() {
    Class<T> type = null;
    Class<?> iter = getClass();
    while (iter.getSuperclass() != null) {
      Class<?> next = iter.getSuperclass();
      if (next != null && next.isAssignableFrom(RootGeneric.class)) {
        type =
            (Class<T>)
                ((ParameterizedType) iter.getGenericSuperclass()).getActualTypeArguments()[0];
        break;
      }
      iter = next;
    }
    if (type == null) {
      throw new ClassCastException("Cannot determine type of T");
    }
    return type;
  }
}

-1

ব্যবহার করুন:

Class<?> typeOfTheList = aListWithTypeSpiderMan.toArray().getClass().getComponentType();

এটা ভুল. toArray()আয় Object[]। আপনি এটি নির্দিষ্ট উপপ্রকারের উপর নির্ভর করতে পারবেন না এবং করা উচিত নয়।
রেডিওডেফ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.