Çalışma zamanında genel sınıf türü edinin


508

Bunu nasıl başarabilirim?

public class GenericClass<T>
{
    public Type getMyType()
    {
        //How do I return the type of T?
    }
}

Şimdiye kadar denediğim her şey her zaman Objectkullanılan özel tip yerine türü döndürür .


3
@SamuelVidal Bu .NET değil, bu Java.
Frontear

Yanıtlar:


317

Diğerlerinin de belirttiği gibi, sadece belirli durumlarda yansıma yoluyla mümkündür.

Gerçekten türe ihtiyacınız varsa, bu her zamanki (tipte güvenli) geçici çözüm şeklidir:

public class GenericClass<T> {

     private final Class<T> type;

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

     public Class<T> getMyType() {
         return this.type;
     }
}

58
Bu yanıtı seviyorum ama örneklemek biraz hantal: GenericClass <AnotherClass> g = new GenericClass <AnotherClass> (AnotherClass.class);
Eliseo Ocampos

1
Bir dao / fabrika / yönetici yaklaşımı kullanırsanız daha da ayrıntılı. Foo foo1 = GetDao<Foo>(Foo.class).get(Foo.class, 1)
djmj

2
Bu doğru, ancak konteyner / yansıma ile somutlaştırılan durumsuz uzak fasulye gibi tüm durumlarda çalışmıyor.
djmj

6
Tıpkı önceki yorumumun bir devamı olarak - yansıma ile oynayan çok fazla acıdan sonra, bu cevabı kullandım.
Tomáš Zato - Monica'yı

18
Genel bir statik fabrika yöntemi sağlayarak gereksiz referansın üstesinden gelebilirsiniz. Böyle bir şey public static <T> GenericClass<T> of(Class<T> type) {...}ve sonra gibi diyoruz: GenericClass<String> var = GenericClass.of(String.class). Biraz daha hoş.
Joeri Hendrickx

262

Böyle bir şey gördüm

private Class<T> persistentClass;

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

içinde hazırda GenericDataAccessObjects Örnek


84
Bu teknik, type parametresinin üst üst sınıfta tanımlandığı yerde çalışır, ancak type parametresi tür hiyerarşisinde başka bir yerde tanımlanırsa başarısız olur. Daha karmaşık vakaları işlemek için TypeTools gibi bir şey kullanılabilir. Dokümanlar daha sofistike bir Genel DAO örneğini içerir.
Jonathan

25
Bu yalnızca bir CLASS genel bildirimleri olan bir şey uyguladığında / genişlettiğinde kullanılan gerçek tür parametrelerini döndürür, bir INSTANCE somutlaştırıldığında kullanılan gerçek tür parametrelerini döndürmez . Başka bir deyişle, CAN içinde söylemek class A implements Comparable<String>, gerçek tip parametresidir String, ancak CAN NOT içinde söylemek Set<String> a = new TreeSet<String>(), gerçek tip parametredir String. Aslında, tür parametre bilgileri, diğer cevaplarda açıklandığı gibi, derlemeden sonra "silinir".
Siu Ching Pong -Asuka Kenji-

32
java.lang.Class cannot be cast to java.lang.reflect.ParameterizedTypeBu cevabı alacağım .
Tomáš Zato - Monica'yı yeniden görevlendir

4
Bu yaklaşım Class-MateJackson milletinden de elde edilebilir . Buraya bir gist
yunspace

5
@ TomášZato Sadece yukarıdaki kodu çağırmak aynı istisnayı benim için döndürdü. Biraz geç olduğunu biliyorum, ama yine de, benim durumumda, (Class<T>) ((ParameterizedType)getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments()gerçek tür argümanlarına ulaşmak için çağırmak zorunda kaldım.
AndrewMcCoist

98

Jenerik değildir şeyleşmiş çalışma anında. Bu, bilginin çalışma zamanında mevcut olmadığı anlamına gelir.

Geriye dönük uyumluluğu korurken Java'ya jenerikler eklemek bir tur-güçtü (bununla ilgili seminal makaleyi görebilirsiniz: Geleceği geçmiş için güvenli kılmak: Java programlama diline jeneriklik eklemek ).

Konuyla ilgili zengin bir literatür var ve bazı insanlar mevcut durumdan memnun değil , bazıları aslında bir cazibesi olduğunu ve buna gerçek bir ihtiyaç olmadığını söylüyor . Her iki bağlantıyı da okuyabilirsiniz, onları oldukça ilginç buldum.


179
Tabii ki memnun kalmadık, .NET'in çok daha iyi bir genel taşıma mekanizması var
Pacerier

6
@Pacerier: ancak tek başına bilinen jenerikler Java'yı .NET düzeyine getirmez. Değer türleri, bunlar için özel bir kod, .NET'in jenerik alanında neden daha iyi olduğu için aynı derecede önemlidir.
Joachim Sauer

@ JoachimSauer, evet değer türleri. Java'da olanları her zaman isterdim. BTW özel kodla ne demek istiyorsun?
Pacerier

3
@ spaaarky21 Hayır, genel tür parametreleri derleme sırasında kaldırılır ("silme" olarak adlandırılır, Google'da yapabilirsiniz). FrVaBe'nin cevabındaki hile sadece üst sınıfın tip parametreleri statik olarak biliniyorsa işe yarar (Johnathn'ın ilk yorumuna bakın)
ewernli

1
Java tipi silme tarihi bir tasarım hatasıdır; Etrafında dolaşmak için onu yazmaktan daha fazla kod yazılmıştır.
Abhijit Sarkar

68

Guava kullanın.

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
  }
}

Bir süre önce, ben soyut sınıflar ve alt sınıflar da dahil olmak üzere bazı tam fledge örneklerini yayınlanmıştır burada .

Not: Bu bir örneğini gerektirir alt sınıf arasında GenericClassdoğru türü parametresi bağlamak böylece. Aksi takdirde, türü yalnızca olarak döndürür T.


3
Boş bir anonim alt sınıf oluşturduğuma dikkat edin (sondaki iki kıvırcık ayraça bakın). Bu, Java'nın çalışma zamanı türü silinmesiyle savaşmak için yansımayı kullanır. Buradan daha fazla bilgi edinebilirsiniz: code.google.com/p/guava-libraries/wiki/ReflectionAçıklama
Cody A. Ray

3
@ CodyA.Ray Kodunuz a java.lang.IllegalArgumentException: class com.google.common.reflect.TypeToken isn't parameterized. Bu yüzden hattı new TypeToken(getClass()) { }olarak değiştirdim new TypeToken<T>(getClass()) { }. Şimdi, kod iyi çalışıyor, ancak Type hala 'T'. Şuna
Manu Manjunath

3
@Dominik Lütfen kendinizi test etmek için kopyalayıp yapıştırabileceğiniz güncellenmiş örneğe bakın. Ayrıca, bir alt sınıfı başlatmanız gerektiğini açıklayan bir not ekledim (gösterildiği gibi). Genel bir görgü kuralları önerisi olarak, bir "arzulu düşünme" posteriyle suçlamadan önce lütfen bağlantılı makaleleri ve ilgili javadokları okuyun. Benzer üretim kodunu birçok kez kullandım. Gösterdiğim Guava yardımcıları bu tam kullanım durumu için tasarlanmıştır ve javadokları bu soruya neredeyse kesin bir cevap vermektedir. docs.guava-libraries.googlecode.com/git/javadoc/com/google/…
Cody A. Ray

1
Bu cevap Java8 ile harika çalışıyor - Çeşitli tipler yayan bir arayüze ve fabrika sınıfına sahibim ve kullanıcıların türü kolayca belirleyebilmelerini istedim. Arabirimde varsayılan yöntemi ekledim: default Type getParameterType() { final TypeToken<T> typeToken = new TypeToken<T>(getClass()) {}; final Type type = typeToken.getType(); return type; }
Richard Sand

2
@ CodyA.Ray Bu yalnızca alt sınıflarıyla çalıştığından GenericClass, bu sınıfı abstractyanlış kullanımın derlememesi için yapmalısınız .
Martin

37

Tabi ki yapabilirsin.

Java, geriye dönük uyumluluk nedeniyle bilgileri çalışma zamanında kullanmaz . Ama bilgi aslında mevcut meta veri olarak mevcuttur ve yansıma yoluyla erişilebilir (ancak yine de tür denetimi için kullanılmaz).

Resmi API'dan:

http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29

Ancak , senaryonuz için yansımayı kullanmam. Şahsen bunu çerçeve kodu için kullanmaya meyilliyim. Senin durumunda sadece bir yapıcı parametre olarak eklemek istiyorum.


10
getActualTypeArguments yalnızca hemen sınıf için tür argümanlarını döndürür. T'nin hiyerarşinin herhangi bir yerinde parametreleştirilebileceği karmaşık bir tür hiyerarşiniz varsa, bunun ne olduğunu bulmak için biraz iş yapmanız gerekir. Bu, TypeTools'un az çok yaptığı şeydir .
Jonathan

36

Java jenerikleri çoğunlukla derleme süresidir, bu da tür bilgisinin çalışma zamanında kaybolduğu anlamına gelir.

class GenericCls<T>
{
    T t;
}

gibi bir şeye derlenecek

class GenericCls
{
   Object o;
}

Çalışma zamanında tür bilgilerini almak için bunu ctor argümanı olarak eklemeniz gerekir.

class GenericCls<T>
{
     private Class<T> type;
     public GenericCls(Class<T> cls)
     {
        type= cls;
     }
     Class<T> getType(){return type;}
}

Misal:

GenericCls<?> instance = new GenericCls<String>(String.class);
assert instance.getType() == String.class;

9
private final Class<T> type;
naXa

Nasıl ondan bir dizi türü oluşturabilirim:Type t = //String[]
Pawel Cioch

@PawelCioch java.lang.reflect.Array.newInstance (elementtype, length); umarım bu yardımcı olur (javadoc burada bulunabilir docs.oracle.com/javase/8/docs/api/java/lang/reflect/… )
josefx

@PawelCioch, oluşturulan diziden türü almak için bir .getClass () yöntemini kaçırdı. Dizi sınıfı almanın doğrudan bir yolu yok gibi görünüyor. Çoğu Java koleksiyonu bunun yerine Object [] kullanır.
josefx

23
public abstract class AbstractDao<T>
{
    private final Class<T> persistentClass;

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

3
Bu cevabı destekliyorum çünkü sorulan soru için işe yarayan bir çözüm. Ancak, birden fazla Genel sınıfla kendim gibi sınıf hiyerarşisinde yukarı doğru gitmek isteyenler için bu işe yaramaz. Çünkü gerçek sınıf yerine java.lang.object alacaksınız.
KMC

3
Bu çözümün YALNIZCA jenerik tipte olan sınıf ÖZET
BabaNew

Java 11'deki soyut
sınıfımla çalışmadı

@JRA_TLL Görünüşe göre yanlış bir şey yaptınız. Ben sadece Java 12 ile kullandım ve bir cazibe gibi çalışır.
Googie

Görünüm hiyerarşisinde yukarı gitmek istiyorsanız genericSuperclass öğesini Sınıf <*> 'ya atabilir ve genericSuperclass'ı alabilirsiniz. Tercihen bir döngü içinde.
fupduck

21

Takip yaklaşımını kullandım:

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();
    }
}

9
Bu örnek kodla: "java.lang.Class java.lang.reflect.ParameterizedType için döküm edilemez java.lang.ClassCastException 'Ben' parçacığı" ana var
yuyang

16

Yapabileceğinizi sanmıyorum, Java derleme yaparken tür silme kullanır, böylece kodunuz jenerikler tarafından oluşturulan uygulamalar ve kütüphanelerle uyumludur.

Oracle Dokümanlar'dan:

Türü Silme

Derleme zamanında daha sıkı tip kontroller sağlamak ve genel programlamayı desteklemek için Java diline jenerikler tanıtıldı. Jenerikleri uygulamak için Java derleyicisi aşağıdakilere tür silme uygular:

Genel türlerdeki tüm tür parametrelerini sınırları ile veya tür parametreleri sınırsızsa Object ile değiştirin. Bu nedenle üretilen bayt kodu sadece sıradan sınıflar, arayüzler ve yöntemler içerir. Tip güvenliğini korumak için gerekirse tip kalıpları yerleştirin. Genişletilmiş jenerik tiplerde polimorfizmi korumak için köprü yöntemleri oluşturun. Tür silme, parametreli türler için yeni sınıf oluşturulmamasını sağlar; sonuç olarak, jenerikler çalışma zamanı yükü oluşturmazlar.

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html


Jup, bu imkansız. Java'nın çalışması için birleşik jeneriklere ihtiyacı olacaktır.
Henning

15

Ian Robertson tarafından bu makalede açıklanan teknik benim için çalışıyor.

Kısaca hızlı ve kirli örnek:

 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;
    }
  }

3
Bu koddaki hangi satırda gerçek, çalışma zamanı türü parametreleri okunuyor?
Ivan Matavulj

buraya? Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Ondrej Bozek

9

Bence başka bir zarif çözüm daha var.

Yapmak istediğiniz şey (güvenli bir şekilde) genel tip parametresinin türünü concete sınıfından süper sınıfa "geçirmektir".

Sınıf türünü sınıfta "meta veri" olarak düşünmenize izin verirseniz, bu, çalışma zamanında meta verileri kodlamak için Java yöntemini gösterir: ek açıklamalar.

İlk olarak şu satırlar boyunca özel bir ek açıklama tanımlayın:

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EntityAnnotation {
    Class entityClass();
}

Daha sonra ek açıklamayı alt sınıfınıza eklemeniz gerekebilir.

@EntityAnnotation(entityClass =  PassedGenericType.class)
public class Subclass<PassedGenericType> {...}

Daha sonra temel sınıfınızda sınıf türünü almak için bu kodu kullanabilirsiniz:

import org.springframework.core.annotation.AnnotationUtils;
.
.
.

private Class getGenericParameterType() {
    final Class aClass = this.getClass();
    EntityAnnotation ne = 
         AnnotationUtils.findAnnotation(aClass, EntityAnnotation.class);

    return ne.entityClass();
}

Bu yaklaşımın bazı sınırlamaları:

  1. Genel türü (PassedGenericType ) DRY olmayan bir tane yerine İKİ yerde .
  2. Bu ancak somut alt sınıfları değiştirebiliyorsanız mümkündür.

Evet, DRY değildir, ancak yukarıda önerilen genişletme yaklaşımından daha temizdir. Bunu sevdim. teşekkürler
agodinhost

8

Bu benim çözümüm:

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);
      }
    }
  }
}

10
Bu, bu sorunun cevabı değil.
Adam Arold

1
Kodum, sorunun tam çözümü değil. Sınıfın genel tür parametrelerini döndürür, ancak gerçek T türünü döndürmez. Ancak soruya rastlayan ve çözümümü arayan başkaları için yararlı olabilir.
Matthias M

1
getClass (). getGenericSuperclass () aynı efekti elde edecektir.
Gorki

5

İşte çalışma çözümü !!!

@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 <> ");
        }
    } 

NOTLAR: Yalnızca üst sınıf
1 olarak kullanılabilir. Yazılan sınıf ( Child extends Generic<Integer>) ile genişletilmesi gerekir
VEYA

2. Anonim uygulama ( new Generic<Integer>() {};) olarak oluşturulması gerekir


4

Yapamazsın. Sınıfa T türünde bir üye değişken eklerseniz (bunu başlatmanız bile gerekmez), türü kurtarmak için bunu kullanabilirsiniz.


2
Hata! Sen do yapıcı onu başlatılması gerekir.
andrewmu

4

İşte bir veya iki kez kullanmam gereken bir yol:

public abstract class GenericClass<T>{
    public abstract Class<T> getMyType();
}

İle birlikte

public class SpecificClass extends GenericClass<String>{

    @Override
    public Class<String> getMyType(){
        return String.class;
    }
}

4
Bu teknik olarak işe yarıyor, ancak genel durumu çözmüyor ve bence orijinal posterin peşinde.
ggb667

Bu, olduğu gibi oylanmayı hak etmiyor - orijinal poster açık değil. Bu cevap , genel sınıfı soyutlaştırmaya uygun olması koşuluyla , işe yarayan ve uygulanması kolay bir tasarım deseni sunar .
VirtualMichael

4

Bu kabin için basit bir çözüm aşağıdaki gibi olabilir

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());
    }
}

3

Burada bazı cevapları tamamlamak için, özyineleme yardımı ile hiyerarşi ne kadar yüksek olursa olsun, MyGenericClass ParametrizedType almak zorunda kaldı:

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());
    }
}

1

İşte benim hile:

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();
    }

}

1
Not: bir tür değişkeni olduğunda bu çalışmazT . TBir tür değişkeni olması durumunda , varargs bir silme dizisi oluşturur T. Bkz. Örneğin http://ideone.com/DIPNwd .
Radiodef

1
Bu "Nesne" döndürür
yahya

Başka bir soruya cevap vermeye çalışıyor olabilirsiniz
Khan

1

Genel türü kullanarak bir değişkeni depolamanız durumunda, getClassType yöntemini aşağıdaki gibi ekleyerek bu sorunu kolayca çözebilirsiniz:

public class Constant<T> {
  private T value;

  @SuppressWarnings("unchecked")
  public Class<T> getClassType () {
    return ((Class<T>) value.getClass());
  }
}

Aşağıdaki gibi verilen bir sınıf örneği olup olmadığını denetlemek için sağlanan sınıf nesnesini daha sonra aşağıdaki gibi kullanın:

Constant<?> constant = ...;
if (constant.getClassType().equals(Integer.class)) {
    Constant<Integer> integerConstant = (Constant<Integer>)constant;
    Integer value = integerConstant.getValue();
    // ...
}

2
Maalesef bu sorunlu. Her şeyden önce, ne olur valueise null? İkincisi, ya valuebir alt sınıf ise T? Constant<Number> c = new Constant<Number>(new Integer(0)); Class<Number> n = c.getClassType();geri Integer.classdönmesi gerektiğinde döner Number.class. Geri dönmek daha doğru olurdu Class<? extends T>. Integer.class bir Class<? extends Number> ama değil a Class<Number>.
Radiodef

1

İşte benim çözümüm

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;
    }
}

Sınıf hiyerarşiniz kaç seviye olursa olsun, bu çözüm hala işe yarar, örneğin:

public class FirstLevelChild<T> extends GenericClass<T> {

}

public class SecondLevelChild extends FirstLevelChild<String> {

}

Bu durumda, getMyType () = java.lang.String


Bu o kadar kodu Sınıfı <T> için Type gizli için başarısız yanında java.lang.String değil T dönüyor T. türü döndüren değil
Mohy Eldeen

İşte yaptığım çevrimiçi bir örnek. Derle ve çalıştır'ı tıklayın, ardından sonucu alabilirsiniz. tutorialspoint.com/...
Lin Yu Cheng

Benim için çalışıyor - WildFly Weld CDI alternatif bir yöntem kırdı.
Andre

Ben varException 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)
yuyang

0
public static final Class<?> getGenericArgument(final Class<?> clazz)
{
    return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
}

0

İşte benim çözümüm. Örnekler bunu açıklamalıdır. Tek gereksinim, bir alt sınıfın bir nesne değil, genel türü ayarlaması gerektiğidir.

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;
    }

}

-1

Yukarıda @Moesio ile aynı şeyi yaptım ama Kotlin'de bu şekilde yapılabilir:

class A<T : SomeClass>() {

    var someClassType : T

    init(){
    this.someClassType = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>
    }

}

-4

Birisi için yararlı olabilir. Java.lang.ref.WeakReference kullanabilirsiniz; bu yoldan:

class SomeClass<N>{
  WeakReference<N> variableToGetTypeFrom;

  N getType(){
    return variableToGetTypeFrom.get();
  }
}

Bu sınıfın nasıl kullanılması gerekiyor? Neden WeakReference? Lütfen sadece bazı kodları değil cevabınızı biraz açıklayınız.
Abhijit Sarkar

Yani bir SomeClass<MyClass> örneğiniz varsa, bu örneği başlatabilir SomeClassve çağırabilirsiniz getTypeve çalışma zamanına sahip olabilirsiniz MyClass.
TheLetch

Tabii, ama neden WeakReference? Söyledikleriniz diğer cevapların çoğundan farklı değil.
Abhijit Sarkar

Birincisi benim yaklaşımım daha kısa (daha az kod), ikincisi Zayıf referanslar, referanslarının sonuçlandırılabilmesini engellemiyor ve bildiğim kadarıyla yansıma kullanmıyor, bu yüzden hızlı
TheLetch

Bu, bu, bilginize, sen sargının anlamıyla her türlü ile yapabileceğiniz bu tür, bir nesne döndürür, bir şey türünü almaz ( AtomicReference, List, Set).
Frontear

-5

Bunu basit, anlaşılır ve kolayca açıklanabilir bir çözüm olarak buldum

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);
    }
}

Açıkla (T...t). (Bu yüzden bu kod çalışmaz.)
Christopher Schneider
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.