আমার আছে;
List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();
তালিকার জেনেরিক ধরণের পুনরুদ্ধার করার কি (সহজ) উপায় আছে?
আমার আছে;
List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();
তালিকার জেনেরিক ধরণের পুনরুদ্ধার করার কি (সহজ) উপায় আছে?
উত্তর:
সেগুলি যদি একটি নির্দিষ্ট শ্রেণীর ক্ষেত্র হয় তবে আপনি প্রতিবিম্বের সামান্য সহায়তায় এগুলি পেতে পারেন:
package test;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
public class Test {
List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();
public static void main(String... args) throws Exception {
Field stringListField = Test.class.getDeclaredField("stringList");
ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType();
Class<?> stringListClass = (Class<?>) stringListType.getActualTypeArguments()[0];
System.out.println(stringListClass); // class java.lang.String.
Field integerListField = Test.class.getDeclaredField("integerList");
ParameterizedType integerListType = (ParameterizedType) integerListField.getGenericType();
Class<?> integerListClass = (Class<?>) integerListType.getActualTypeArguments()[0];
System.out.println(integerListClass); // class java.lang.Integer.
}
}
প্যারামিটারের ধরণ এবং রিটার্ন ধরণের পদ্ধতিগুলির জন্য আপনি এটিও করতে পারেন।
কিন্তু যদি তারা শ্রেণি / পদ্ধতির যেখানে আপনি তাদের সম্পর্কে জানতে হবে সেই একই ক্ষেত্রের মধ্যে থাকেন তবে তাদের জানার কোনও লাভ নেই, কারণ আপনি ইতিমধ্যে তাদের নিজেরাই ঘোষণা করেছেন।
<?>
পরিবর্তে (ওয়াইল্ডকার্ড প্রকার) ব্যবহার করছে <Class>
। আপনার <?>
দ্বারা <Class>
বা যাই হোক না কেন প্রতিস্থাপন করুন <E>
।
আপনি পদ্ধতি প্যারামিটারগুলির জন্যও একই কাজটি করতে পারেন:
Type[] types = method.getGenericParameterTypes();
//Now assuming that the first parameter to the method is of type List<Integer>
ParameterizedType pType = (ParameterizedType) types[0];
Class<?> clazz = (Class<?>) pType.getActualTypeArguments()[0];
System.out.println(clazz); //prints out java.lang.Integer
সংক্ষিপ্ত উত্তর: না।
এটি সম্ভবত একটি সদৃশ, এখনই উপযুক্ত খুঁজে পাচ্ছেন না।
জাভা টাইপ ইরেজর নামক কিছু ব্যবহার করে যার অর্থ রানটাইম উভয় বস্তু সমান। সংকলকটি জানে তালিকাগুলিতে পূর্ণসংখ্যা বা স্ট্রিং রয়েছে এবং যেমন কোনও ধরণের নিরাপদ পরিবেশ বজায় রাখতে পারে। রানটাইমের সময় এই তথ্যটি (কোনও বস্তুর উদাহরণের ভিত্তিতে) হারিয়ে গেছে এবং তালিকায় কেবল 'অবজেক্ট' রয়েছে।
আপনি ক্লাস সম্পর্কে কিছুটা জানতে পারেন, এটি কী ধরণের দ্বারা প্যারামিটারাইজড হতে পারে, তবে সাধারণত এটি এমন কিছু যা "অবজেক্ট", অর্থাৎ যেকোন কিছুতে প্রসারিত করে। যদি আপনি কোনও প্রকারটি সংজ্ঞায়িত করেন
class <A extends MyClass> AClass {....}
AClass.class কেবলমাত্র প্যারামিটার A মাইক্লাস দ্বারা আবদ্ধ তা কেবল থাকবে, তবে এর চেয়ে বেশি বলার উপায় নেই।
List<Integer>
এবং হিসাবে ঘোষণা করছেন List<String>
; এই ক্ষেত্রে, মুছে ফেলা প্রযোজ্য নয়।
জেনেরিক ধরণের সংগ্রহের বিষয়টি কেবল তখনই বিবেচনা করা উচিত যখন এটির মধ্যে এটির বস্তু রয়েছে, তাই না? সুতরাং কেবল এটি করা সহজ নয়:
Collection<?> myCollection = getUnknownCollectionFromSomewhere();
Class genericClass = null;
Iterator it = myCollection.iterator();
if (it.hasNext()){
genericClass = it.next().getClass();
}
if (genericClass != null) { //do whatever we needed to know the type for
রানটাইমের ক্ষেত্রে জেনেরিক টাইপের মতো কোনও জিনিস নেই, তবে রানটাইমের সময় ভিতরে থাকা জিনিসগুলি ঘোষিত জেনেরিকের মতো একই ধরণের গ্যারান্টিযুক্ত, সুতরাং এটি প্রক্রিয়া করার আগে কেবল আইটেমটির শ্রেণি পরীক্ষা করা যথেষ্ট সহজ।
অন্য যে জিনিসটি আপনি করতে পারেন তা হ'ল অন্যদের উপেক্ষা করে (বা তাদের আলাদাভাবে প্রক্রিয়াজাত করা) সঠিক ধরণের সদস্যদের জন্য তালিকাটি প্রক্রিয়া করা।
Map<Class<?>, List<Object>> classObjectMap = myCollection.stream()
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(Object::getClass));
// Process the list of the correct class, and/or handle objects of incorrect
// class (throw exceptions, etc). You may need to group subclasses by
// filtering the keys. For instance:
List<Number> numbers = classObjectMap.entrySet().stream()
.filter(e->Number.class.isAssignableFrom(e.getKey()))
.flatMap(e->e.getValue().stream())
.map(Number.class::cast)
.collect(Collectors.toList());
এটি আপনাকে এমন সমস্ত আইটেমের একটি তালিকা দেবে যার ক্লাসগুলি সাবক্লাস ছিল Number
যার পরে আপনি প্রয়োজন অনুযায়ী প্রক্রিয়া করতে পারেন। বাকি আইটেমগুলি অন্য তালিকায় ফিল্টার করা হয়েছিল। তারা মানচিত্রে থাকাকালীন, আপনি এগুলি পছন্দসই হিসাবে প্রক্রিয়া করতে পারেন বা তাদের উপেক্ষা করতে পারেন।
আপনি যদি অন্য শ্রেণীর আইটেমগুলি পুরোপুরি উপেক্ষা করতে চান তবে এটি অনেক সহজ হয়ে যায়:
List<Number> numbers = myCollection.stream()
.filter(Number.class::isInstance)
.map(Number.class::cast)
.collect(Collectors.toList());
এমনকি কোনও তালিকার মধ্যে নির্দিষ্ট শ্রেণীর সাথে মেলে এমন আইটেম রয়েছে তা নিশ্চিত করার জন্য আপনি এমনকি একটি ইউটিলিটি পদ্ধতি তৈরি করতে পারেন:
public <V> List<V> getTypeSafeItemList(Collection<Object> input, Class<V> cls) {
return input.stream()
.filter(cls::isInstance)
.map(cls::cast)
.collect(Collectors.toList());
}
Object
এবং যখন আপনি সেগুলি তালিকা থেকে টেনে আনবেন, আপনি তাদের ধরণের ভিত্তিতে একটি উপযুক্ত হ্যান্ডলারের হাতে দিতে চাইবেন।
একটি ক্ষেত্রের জেনেরিক ধরণের সন্ধানের জন্য:
((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]).getSimpleName()
আপনার যদি জেনেরিক প্রকারের ফেরত প্রকারের দরকার হয় তবে আমি যখন এই ক্লাসে কোন পদ্ধতি ফিরে পেয়েছি Collection
এবং তার জেনেরিক ধরণগুলি অ্যাক্সেস করতে চাই তখন আমি এই পদ্ধতিটি ব্যবহার করি :
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
public class Test {
public List<String> test() {
return null;
}
public static void main(String[] args) throws Exception {
for (Method method : Test.class.getMethods()) {
Class returnClass = method.getReturnType();
if (Collection.class.isAssignableFrom(returnClass)) {
Type returnType = method.getGenericReturnType();
if (returnType instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) returnType;
Type[] argTypes = paramType.getActualTypeArguments();
if (argTypes.length > 0) {
System.out.println("Generic type is " + argTypes[0]);
}
}
}
}
}
}
এই ফলাফলগুলি:
জেনেরিক ধরণটি java.lang.String শ্রেণি
স্টিভ কে এর উত্তরে প্রসারিত:
/**
* Performs a forced cast.
* Returns null if the collection type does not match the items in the list.
* @param data The list to cast.
* @param listType The type of list to cast to.
*/
static <T> List<? super T> castListSafe(List<?> data, Class<T> listType){
List<T> retval = null;
//This test could be skipped if you trust the callers, but it wouldn't be safe then.
if(data!=null && !data.isEmpty() && listType.isInstance(data.iterator().next().getClass())) {
@SuppressWarnings("unchecked")//It's OK, we know List<T> contains the expected type.
List<T> foo = (List<T>)data;
return retval;
}
return retval;
}
Usage:
protected WhateverClass add(List<?> data) {//For fluant useage
if(data==null) || data.isEmpty(){
throw new IllegalArgumentException("add() " + data==null?"null":"empty"
+ " collection");
}
Class<?> colType = data.iterator().next().getClass();//Something
aMethod(castListSafe(data, colType));
}
aMethod(List<Foo> foo){
for(Foo foo: List){
System.out.println(Foo);
}
}
aMethod(List<Bar> bar){
for(Bar bar: List){
System.out.println(Bar);
}
}
রানটাইমের সময়, না, আপনি পারবেন না।
তবে প্রতিফলন মাধ্যমে টাইপ প্যারামিটার হয় প্রবেশযোগ্য। চেষ্টা
for(Field field : this.getDeclaredFields()) {
System.out.println(field.getGenericType())
}
পদ্ধতিটি getGenericType()
একটি টাইপ অবজেক্ট প্রদান করে। এক্ষেত্রে এটি একটি উদাহরণ হবে ParametrizedType
, যার পরিবর্তে পদ্ধতি রয়েছে getRawType()
(যার List.class
মধ্যে রয়েছে এই পদ্ধতিতে অন্তর্ভুক্ত থাকবে ) এবং getActualTypeArguments()
, যা একটি অ্যারে (এই ক্ষেত্রে, দৈর্ঘ্যের এক, উভয়ই থাকবে String.class
বা Integer.class
) প্রদান করবে।
method.getGenericParameterTypes()
কোনও পদ্ধতির পরামিতিগুলির ঘোষিত ধরণের পেতে ব্যবহার করতে পারেন ।
একই সমস্যা ছিল, তবে আমি পরিবর্তে উদাহরণ ব্যবহার করেছি। এটি এইভাবে করেছেন:
List<Object> listCheck = (List<Object>)(Object) stringList;
if (!listCheck.isEmpty()) {
if (listCheck.get(0) instanceof String) {
System.out.println("List type is String");
}
if (listCheck.get(0) instanceof Integer) {
System.out.println("List type is Integer");
}
}
}
এটিতে চেক না করা কাস্ট ব্যবহার করা জড়িত তাই যখন আপনি জানেন যে এটি একটি তালিকা, এবং এটি কী ধরণের হতে পারে তখনই এটি করুন।
অন্যরা যেমন বলেছে, কেবলমাত্র সঠিক উত্তর হ'ল না, প্রকারটি মুছে ফেলা হয়েছে।
যদি তালিকার একটি শূন্য-সংখ্যা উপাদান থাকে তবে আপনি প্রথম উপাদানটির ধরণটি (উদাহরণস্বরূপ, এটি getClass পদ্ধতি ব্যবহার করে) অনুসন্ধান করতে পারেন। এটি আপনাকে তালিকার জেনেরিক প্রকারটি বলবে না, তবে এটি ধরে নেওয়া যুক্তিযুক্ত যে জেনেরিক টাইপটি তালিকার ধরণের কয়েকটি ধরণের সুপারক্লাস ছিল।
আমি পদ্ধতির পক্ষে চাই না, তবে একটি বাঁধাইয়ের ক্ষেত্রে এটি কার্যকর হতে পারে।
List<Integer>
এবং হিসাবে ঘোষণা করছেন List<String>
; এই ক্ষেত্রে, মুছে ফেলা প্রযোজ্য নয়।
import org.junit.Assert;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class GenericTypeOfCollectionTest {
public class FormBean {
}
public class MyClazz {
private List<FormBean> list = new ArrayList<FormBean>();
}
@Test
public void testName() throws Exception {
Field[] fields = MyClazz.class.getFields();
for (Field field : fields) {
//1. Check if field is of Collection Type
if (Collection.class.isAssignableFrom(field.getType())) {
//2. Get Generic type of your field
Class fieldGenericType = getFieldGenericType(field);
//3. Compare with <FromBean>
Assert.assertTrue("List<FormBean>",
FormBean.class.isAssignableFrom(fieldGenericType));
}
}
}
//Returns generic type of any field
public Class getFieldGenericType(Field field) {
if (ParameterizedType.class.isAssignableFrom(field.getGenericType().getClass())) {
ParameterizedType genericType =
(ParameterizedType) field.getGenericType();
return ((Class)
(genericType.getActualTypeArguments()[0])).getSuperclass();
}
//Returns dummy Boolean Class to compare with ValueObject & FormBean
return new Boolean(false).getClass();
}
}
getFieldGenericTypefieldGenericType
এটি কী খুঁজে পাওয়া যায় না
প্রকারটি মোছা হয়েছে তাই আপনি সক্ষম হবেন না। দেখুন http://en.wikipedia.org/wiki/Type_erasure এবং http://en.wikipedia.org/wiki/Generics_in_Java#Type_erasure
List<Integer>
এবং হিসাবে ঘোষণা করছেন List<String>
; এই ক্ষেত্রে, মুছে ফেলা প্রযোজ্য নয়।
Field
এগুলির জন্য প্রতিচ্ছবিটি ব্যবহার করুন তবে আপনি ঠিক করতে পারেন: field.genericType
জেনেরিক সম্পর্কেও তথ্য রয়েছে এমন টাইপটি পেতে।