উত্তর:
অন্যরা যেমন উল্লেখ করেছে, নির্দিষ্ট পরিস্থিতিতে প্রতিবিম্বের মাধ্যমে এটি কেবল সম্ভব।
আপনার যদি সত্যিই টাইপের দরকার হয় তবে এটি হ'ল স্বাভাবিক (টাইপ-সেফ) ওয়ার্কআরাউন্ড প্যাটার্ন:
public class GenericClass<T> {
private final Class<T> type;
public GenericClass(Class<T> type) {
this.type = type;
}
public Class<T> getMyType() {
return this.type;
}
}
Foo foo1 = GetDao<Foo>(Foo.class).get(Foo.class, 1)
public static <T> GenericClass<T> of(Class<T> type) {...}এবং তারপর যেমন একে ডাকতে: GenericClass<String> var = GenericClass.of(String.class)। কিছুটা ভাল।
আমি এরকম কিছু দেখেছি
private Class<T> persistentClass;
public Constructor() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
মধ্যে হাইবারনেট GenericDataAccessObjects উদাহরণ
class A implements Comparable<String>, প্রকৃত টাইপ প্যারামিটার String, কিন্তু এটা করতে পারে না বলে যে এ Set<String> a = new TreeSet<String>(), প্রকৃত টাইপ প্যারামিটার String। প্রকৃতপক্ষে, টাইপ প্যারামিটার তথ্য সংকলনের পরে "মুছে ফেলা হয়", যেমন অন্যান্য উত্তরে ব্যাখ্যা করা হয়েছে।
java.lang.Class cannot be cast to java.lang.reflect.ParameterizedTypeএই উত্তর পেয়ে যাচ্ছি ।
(Class<T>) ((ParameterizedType)getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments()প্রকৃত ধরণের যুক্তি পেতে কল করতে হয়েছিল।
জেনারিকগুলি রান-টাইমে পুনরায় সংশোধিত হয় না । এর অর্থ রান-টাইমে তথ্য উপস্থিত নেই।
পশ্চাদগম্য সামঞ্জস্যতা জাগ্রত করার সময় জাভাতে জেনেরিক যোগ করা একটি ট্যুর-ডি-ফোর্স ছিল (আপনি এটি সম্পর্কে চূড়ান্ত কাগজটি দেখতে পারেন: ভবিষ্যতের জন্য নিরাপদ করা: জাভা প্রোগ্রামিং ভাষায় উদারতা যোগ করা )।
বিষয়টিতে একটি সমৃদ্ধ সাহিত্য রয়েছে, এবং কিছু লোক বর্তমান অবস্থা সম্পর্কে অসন্তুষ্ট , কেউ কেউ বলে যে এটি আসলে প্রলুব্ধ এবং এর সত্যিকার প্রয়োজন নেই। আপনি উভয় লিঙ্কটি পড়তে পারেন, আমি সেগুলি বেশ আকর্ষণীয় পেয়েছি।
পেয়ারা ব্যবহার করুন।
import com.google.common.reflect.TypeToken;
import java.lang.reflect.Type;
public abstract class GenericClass<T> {
private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) { };
private final Type type = typeToken.getType(); // or getRawType() to return Class<? super T>
public Type getType() {
return type;
}
public static void main(String[] args) {
GenericClass<String> example = new GenericClass<String>() { };
System.out.println(example.getType()); // => class java.lang.String
}
}
কিছুক্ষণ আগে, আমি এখানে অ্যাবস্ট্রাক্ট ক্লাস এবং সাবক্ল্যাসিসহ কয়েকটি পূর্ণদৃষ্টির উদাহরণ পোস্ট করেছি ।
Note: এই প্রয়োজন যে আপনি একটি instantiate উপশ্রেণী এর GenericClassতাই এটি টাইপ প্যারামিটার সঠিকভাবে আবদ্ধ করতে পারেন। অন্যথায় এটি ঠিক হিসাবে টাইপ ফিরে আসবে T।
java.lang.IllegalArgumentException: class com.google.common.reflect.TypeToken isn't parameterized। তাই আমি লাইন পরিবর্তিত new TypeToken(getClass()) { }করতে new TypeToken<T>(getClass()) { }। এখন কোডটি ঠিকঠাক চলছে, তবে প্রকারটি এখনও 'টি'। এটি দেখুন: gist.github.com/m-manu/9cda9d8f9d53bead2035
default Type getParameterType() { final TypeToken<T> typeToken = new TypeToken<T>(getClass()) {}; final Type type = typeToken.getType(); return type; }
GenericClass, আপনার সেই শ্রেণিটি করা উচিত abstractযাতে ভুল ব্যবহার সংকলন না হয়।
অবশ্যই, আপনি পারেন।
জাভা পিছনের সামঞ্জস্যতার কারণে, রান সময়ে তথ্য ব্যবহার করে না । তবে তথ্যটি আসলে উপস্থিত মেটাডেটা হিসাবে এবং প্রতিবিম্বের মাধ্যমে অ্যাক্সেস করা যায় (তবে এটি এখনও টাইপ-চেকিংয়ের জন্য ব্যবহৃত হয় না)।
অফিসিয়াল এপিআই থেকে:
তবে আপনার দৃশ্যের জন্য আমি প্রতিবিম্ব ব্যবহার করব না। আমি ব্যক্তিগতভাবে ফ্রেমওয়ার্ক কোডের জন্য এটি ব্যবহার করতে বেশি আগ্রহী। আপনার ক্ষেত্রে আমি কেবল কনস্ট্রাক্টর প্যারাম হিসাবে টাইপটি যুক্ত করব।
জাভা জেনেরিকগুলি বেশিরভাগ সময়ই সংকলন করে থাকে, এর অর্থ এই যে টাইপ তথ্য রানটাইমে হারিয়ে যায়।
class GenericCls<T>
{
T t;
}
মত কিছু সংকলিত হবে
class GenericCls
{
Object o;
}
রানটাইমে টাইপের তথ্য পেতে আপনাকে এটিকে কর্টারের যুক্তি হিসাবে যুক্ত করতে হবে।
class GenericCls<T>
{
private Class<T> type;
public GenericCls(Class<T> cls)
{
type= cls;
}
Class<T> getType(){return type;}
}
উদাহরণ:
GenericCls<?> instance = new GenericCls<String>(String.class);
assert instance.getType() == String.class;
private final Class<T> type;
Type t = //String[]
public abstract class AbstractDao<T>
{
private final Class<T> persistentClass;
public AbstractDao()
{
this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
}
আমি অনুসরণ পদ্ধতির ব্যবহার করেছি:
public class A<T> {
protected Class<T> clazz;
public A() {
this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
public Class<T> getClazz() {
return clazz;
}
}
public class B extends A<C> {
/* ... */
public void anything() {
// here I may use getClazz();
}
}
আমি মনে করি না আপনি যা করতে পারেন, জাভা সংকলন করার সময় টাইপ ইরেজর ব্যবহার করেন যাতে আপনার কোডটি প্রি-জেনেরিক তৈরি হওয়া অ্যাপ্লিকেশন এবং লাইব্রেরির সাথে সামঞ্জস্যপূর্ণ।
ওরাকল ডক্স থেকে:
Erasure টাইপ করুন
সংকলন সময়ে শক্ততর প্রকারের চেক সরবরাহ এবং জেনেরিক প্রোগ্রামিং সমর্থন করার জন্য জেনারিকসটি জাভা ভাষার সাথে প্রবর্তিত হয়েছিল। জেনেরিকগুলি প্রয়োগ করতে, জাভা সংকলক প্রকারটি মুছে ফেলার জন্য প্রযোজ্য:
সমস্ত ধরণের পরামিতি জেনেরিক প্রকারগুলিকে তাদের সীমানা বা অবজেক্টের সাথে প্রতিস্থাপন করুন যদি প্রকারের পরামিতিগুলি আনবাউন্ড না থাকে। উত্পাদিত বাইটকোডে, কেবলমাত্র সাধারণ ক্লাস, ইন্টারফেস এবং পদ্ধতি রয়েছে। প্রকারের সুরক্ষা সংরক্ষণ করতে প্রয়োজনে টাইপ ক্যাসেটগুলি sertোকান। বর্ধিত জেনেরিক ধরণের পলিমারফিজম সংরক্ষণের জন্য সেতু পদ্ধতি তৈরি করুন। প্রকার মুছে ফেলা নিশ্চিত করে যে পরামিতিযুক্ত ধরণের জন্য কোনও নতুন ক্লাস তৈরি করা হয়নি; ফলস্বরূপ, জেনেরিকগুলি কোনও রানটাইম ওভারহেড ব্যয় করে না।
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
আয়ান রবার্টসনের এই নিবন্ধে বর্ণিত প্রযুক্তিটি আমার পক্ষে কাজ করে।
সংক্ষিপ্ত দ্রুত এবং নোংরা উদাহরণে:
public abstract class AbstractDAO<T extends EntityInterface, U extends QueryCriteria, V>
{
/**
* Method returns class implementing EntityInterface which was used in class
* extending AbstractDAO
*
* @return Class<T extends EntityInterface>
*/
public Class<T> returnedClass()
{
return (Class<T>) getTypeArguments(AbstractDAO.class, getClass()).get(0);
}
/**
* Get the underlying class for a type, or null if the type is a variable
* type.
*
* @param type the type
* @return the underlying class
*/
public static Class<?> getClass(Type type)
{
if (type instanceof Class) {
return (Class) type;
} else if (type instanceof ParameterizedType) {
return getClass(((ParameterizedType) type).getRawType());
} else if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
Class<?> componentClass = getClass(componentType);
if (componentClass != null) {
return Array.newInstance(componentClass, 0).getClass();
} else {
return null;
}
} else {
return null;
}
}
/**
* Get the actual type arguments a child class has used to extend a generic
* base class.
*
* @param baseClass the base class
* @param childClass the child class
* @return a list of the raw classes for the actual type arguments.
*/
public static <T> List<Class<?>> getTypeArguments(
Class<T> baseClass, Class<? extends T> childClass)
{
Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
Type type = childClass;
// start walking up the inheritance hierarchy until we hit baseClass
while (!getClass(type).equals(baseClass)) {
if (type instanceof Class) {
// there is no useful information for us in raw types, so just keep going.
type = ((Class) type).getGenericSuperclass();
} else {
ParameterizedType parameterizedType = (ParameterizedType) type;
Class<?> rawType = (Class) parameterizedType.getRawType();
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
for (int i = 0; i < actualTypeArguments.length; i++) {
resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
}
if (!rawType.equals(baseClass)) {
type = rawType.getGenericSuperclass();
}
}
}
// finally, for each actual type argument provided to baseClass, determine (if possible)
// the raw class for that type argument.
Type[] actualTypeArguments;
if (type instanceof Class) {
actualTypeArguments = ((Class) type).getTypeParameters();
} else {
actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
}
List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
// resolve types by chasing down type variables.
for (Type baseType : actualTypeArguments) {
while (resolvedTypes.containsKey(baseType)) {
baseType = resolvedTypes.get(baseType);
}
typeArgumentsAsClasses.add(getClass(baseType));
}
return typeArgumentsAsClasses;
}
}
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
আমি মনে করি আরও একটি মার্জিত সমাধান আছে।
আপনি যা করতে চান তা হ'ল (নিরাপদে) জেনেরিক টাইপ প্যারামিটারের ধরণটি ক্লাস থেকে শুরু করে সুপার ক্লাসে।
আপনি যদি ক্লাসে ক্লাসের ধরণটিকে "মেটাডেটা" হিসাবে ভাবার অনুমতি দেন, যা রানটাইমে মেটাডেটা এনকোডিংয়ের জন্য জাভা পদ্ধতিটি প্রস্তাব করে: টীকাগুলি।
প্রথমে এই লাইনগুলি বরাবর একটি কাস্টম টীকা সংজ্ঞায়িত করুন:
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EntityAnnotation {
Class entityClass();
}
তারপরে আপনাকে আপনার সাবক্লাসে টীকা যুক্ত করতে হবে।
@EntityAnnotation(entityClass = PassedGenericType.class)
public class Subclass<PassedGenericType> {...}
তারপরে আপনি এই বেসটি আপনার বেস ক্লাসে ক্লাসের ধরণ পেতে ব্যবহার করতে পারেন:
import org.springframework.core.annotation.AnnotationUtils;
.
.
.
private Class getGenericParameterType() {
final Class aClass = this.getClass();
EntityAnnotation ne =
AnnotationUtils.findAnnotation(aClass, EntityAnnotation.class);
return ne.entityClass();
}
এই পদ্ধতির কিছু সীমাবদ্ধতা হ'ল:
PassedGenericType ) টিডব্লিউও স্থানে নন-ডিআরআইয়ের পরিবর্তে ।এটি আমার সমাধান:
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
public class GenericClass<T extends String> {
public static void main(String[] args) {
for (TypeVariable typeParam : GenericClass.class.getTypeParameters()) {
System.out.println(typeParam.getName());
for (Type bound : typeParam.getBounds()) {
System.out.println(bound);
}
}
}
}
এখানে সমাধান কাজ করছে !!!
@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 <> ");
}
}
দ্রষ্টব্য:
কেবলমাত্র সুপারক্লাস হিসাবে ব্যবহার করা যায়
১। টাইপযুক্ত শ্রেণি ( Child extends Generic<Integer>)
বা
2 দিয়ে প্রসারিত করতে হবে 2. বেনামে বাস্তবায়ন হিসাবে তৈরি করতে হবে ( new Generic<Integer>() {};)
আপনি পারবেন না। আপনি ক্লাসে টি টাইপের টি সদস্যের একটি ভেরিয়েবল যুক্ত করলে (আপনি এটি আরম্ভ করতে হবে না), আপনি টাইপটি পুনরুদ্ধার করতে এটি ব্যবহার করতে পারেন।
এখানে একটি উপায় যা আমাকে একবার বা দুবার ব্যবহার করতে হয়েছিল:
public abstract class GenericClass<T>{
public abstract Class<T> getMyType();
}
সাথে
public class SpecificClass extends GenericClass<String>{
@Override
public Class<String> getMyType(){
return String.class;
}
}
এই ক্যাবটির জন্য একটি সহজ সমাধান নীচের মত হতে হবে
public class GenericDemo<T>{
private T type;
GenericDemo(T t)
{
this.type = t;
}
public String getType()
{
return this.type.getClass().getName();
}
public static void main(String[] args)
{
GenericDemo<Integer> obj = new GenericDemo<Integer>(5);
System.out.println("Type: "+ obj.getType());
}
}
এখানে কয়েকটি উত্তর সম্পূর্ণ করতে, আমাকে পুনরাবৃত্তির সাহায্যে হাইয়ারার্কি কতটা উঁচু হোক না কেন প্যারামেট্রিজেড টাইপটি মাইজেনারিক ক্লাসের পেতে হয়েছিল:
private Class<T> getGenericTypeClass() {
return (Class<T>) (getParametrizedType(getClass())).getActualTypeArguments()[0];
}
private static ParameterizedType getParametrizedType(Class clazz){
if(clazz.getSuperclass().equals(MyGenericClass.class)){ // check that we are at the top of the hierarchy
return (ParameterizedType) clazz.getGenericSuperclass();
} else {
return getParametrizedType(clazz.getSuperclass());
}
}
আমার কৌশলটি এখানে:
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(Main.<String> getClazz());
}
static <T> Class getClazz(T... param) {
return param.getClass().getComponentType();
}
}
T । কেস যে Tএকটি টাইপ পরিবর্তনশীল, ভারার্গস এর ইরেজিওর একটি অ্যারের সৃষ্টি T। যেমনঃ http://ideone.com/DIPNwd দেখুন ।
জেনেরিক প্রকারটি ব্যবহার করে আপনি যদি কোনও ভেরিয়েবল সঞ্চয় করেন তবে আপনি সহজেই এই সমস্যাটি সমাধান করতে পারেন একটি getClassType পদ্ধতি যুক্ত করে:
public class Constant<T> {
private T value;
@SuppressWarnings("unchecked")
public Class<T> getClassType () {
return ((Class<T>) value.getClass());
}
}
আমি প্রদত্ত শ্রেণীর অবজেক্টটি পরবর্তীতে এটি কোনও প্রদত্ত শ্রেণীর উদাহরণ কিনা তা পরীক্ষা করতে ব্যবহার করি:
Constant<?> constant = ...;
if (constant.getClassType().equals(Integer.class)) {
Constant<Integer> integerConstant = (Constant<Integer>)constant;
Integer value = integerConstant.getValue();
// ...
}
valueহয় null? সর্বোপরি, যদি valueএকটি সাবক্লাস হয় T? এটি ফিরে Constant<Number> c = new Constant<Number>(new Integer(0)); Class<Number> n = c.getClassType();আসা Integer.classউচিত ফিরে Number.class। ফিরে আসা আরও সঠিক হবে Class<? extends T>। Integer.class একটি Class<? extends Number> কিন্তু একটি না Class<Number>।
এখানে আমার সমাধান
public class GenericClass<T>
{
private Class<T> realType;
public GenericClass() {
findTypeArguments(getClass());
}
private void findTypeArguments(Type t) {
if (t instanceof ParameterizedType) {
Type[] typeArgs = ((ParameterizedType) t).getActualTypeArguments();
realType = (Class<T>) typeArgs[0];
} else {
Class c = (Class) t;
findTypeArguments(c.getGenericSuperclass());
}
}
public Type getMyType()
{
// How do I return the type of T? (your question)
return realType;
}
}
আপনার শ্রেণি শ্রেণিবিন্যাসের কত স্তর রয়েছে তা বিবেচনা না করেই, এই সমাধানটি এখনও কাজ করে, উদাহরণস্বরূপ:
public class FirstLevelChild<T> extends GenericClass<T> {
}
public class SecondLevelChild extends FirstLevelChild<String> {
}
এই ক্ষেত্রে, getMyType () = java.lang.String
Exception in thread "main" java.lang.NullPointerException at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.<init>(Main.java:43) at Main.main(Main.java:61)
এখানে আমার সমাধান। উদাহরণগুলির এটি ব্যাখ্যা করা উচিত। একমাত্র প্রয়োজনীয়তা একটি সাবক্লাস অবশ্যই জেনেরিক প্রকার সেট করতে হবে, কোনও বস্তু নয়।
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;
public class TypeUtils {
/*** EXAMPLES ***/
public static class Class1<A, B, C> {
public A someA;
public B someB;
public C someC;
public Class<?> getAType() {
return getTypeParameterType(this.getClass(), Class1.class, 0);
}
public Class<?> getCType() {
return getTypeParameterType(this.getClass(), Class1.class, 2);
}
}
public static class Class2<D, A, B, E, C> extends Class1<A, B, C> {
public B someB;
public D someD;
public E someE;
}
public static class Class3<E, C> extends Class2<String, Integer, Double, E, C> {
public E someE;
}
public static class Class4 extends Class3<Boolean, Long> {
}
public static void test() throws NoSuchFieldException {
Class4 class4 = new Class4();
Class<?> typeA = class4.getAType(); // typeA = Integer
Class<?> typeC = class4.getCType(); // typeC = Long
Field fieldSomeA = class4.getClass().getField("someA");
Class<?> typeSomeA = TypeUtils.getFieldType(class4.getClass(), fieldSomeA); // typeSomeA = Integer
Field fieldSomeE = class4.getClass().getField("someE");
Class<?> typeSomeE = TypeUtils.getFieldType(class4.getClass(), fieldSomeE); // typeSomeE = Boolean
}
/*** UTILS ***/
public static Class<?> getTypeVariableType(Class<?> subClass, TypeVariable<?> typeVariable) {
Map<TypeVariable<?>, Type> subMap = new HashMap<>();
Class<?> superClass;
while ((superClass = subClass.getSuperclass()) != null) {
Map<TypeVariable<?>, Type> superMap = new HashMap<>();
Type superGeneric = subClass.getGenericSuperclass();
if (superGeneric instanceof ParameterizedType) {
TypeVariable<?>[] typeParams = superClass.getTypeParameters();
Type[] actualTypeArgs = ((ParameterizedType) superGeneric).getActualTypeArguments();
for (int i = 0; i < typeParams.length; i++) {
Type actualType = actualTypeArgs[i];
if (actualType instanceof TypeVariable) {
actualType = subMap.get(actualType);
}
if (typeVariable == typeParams[i]) return (Class<?>) actualType;
superMap.put(typeParams[i], actualType);
}
}
subClass = superClass;
subMap = superMap;
}
return null;
}
public static Class<?> getTypeParameterType(Class<?> subClass, Class<?> superClass, int typeParameterIndex) {
return TypeUtils.getTypeVariableType(subClass, superClass.getTypeParameters()[typeParameterIndex]);
}
public static Class<?> getFieldType(Class<?> clazz, AccessibleObject element) {
Class<?> type = null;
Type genericType = null;
if (element instanceof Field) {
type = ((Field) element).getType();
genericType = ((Field) element).getGenericType();
} else if (element instanceof Method) {
type = ((Method) element).getReturnType();
genericType = ((Method) element).getGenericReturnType();
}
if (genericType instanceof TypeVariable) {
Class<?> typeVariableType = TypeUtils.getTypeVariableType(clazz, (TypeVariable) genericType);
if (typeVariableType != null) {
type = typeVariableType;
}
}
return type;
}
}
এটি কারও কাজে লাগতে পারে। আপনি java.lang.ref.WeakReferences ব্যবহার করতে পারেন; এই পথে:
class SomeClass<N>{
WeakReference<N> variableToGetTypeFrom;
N getType(){
return variableToGetTypeFrom.get();
}
}
WeakReference? আপনার উত্তর সহ কিছু ব্যাখ্যা সরবরাহ করুন, কেবল কিছু কোড নয়।
SomeClass<MyClass> ইনস্ট্যান্টিয়েট করতে পারেন SomeClassএবং getTypeসেই দৃষ্টিতে ফোন করতে পারেন এবং রানটাইমটি হতে পারে MyClass।
WeakReference? আপনি যা বলেছিলেন তা অন্যান্য উত্তরগুলির চেয়ে আলাদা নয়।
AtomicReference, List, Set)।
আমি এটি একটি সহজ বোধগম্য এবং সহজেই ব্যাখ্যাযোগ্য সমাধান হিসাবে পেয়েছি
public class GenericClass<T> {
private Class classForT(T...t) {
return t.getClass().getComponentType();
}
public static void main(String[] args) {
GenericClass<String> g = new GenericClass<String>();
System.out.println(g.classForT());
System.out.println(String.class);
}
}
(T...t)। (এজন্য এই কোডটি কার্যকর হয় না))