programing

범용 타입 T의 클래스인스턴스를 가져오려면 어떻게 해야 하나요?

prostudy 2022. 6. 5. 17:47
반응형

범용 타입 T의 클래스인스턴스를 가져오려면 어떻게 해야 하나요?

는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.Foo<T> .법방 . . ..FooT 저는 안T.class.

이 를 회피할 때론 으로 피하는 것이 좋습니다.T.class

간단히 말하면 Java에서는 범용 타입 파라미터의 런타임타입을 확인할 수 없습니다.상세한 것에 대하여는, Java Tutorial 의 type erase 에 관한 장을 참조해 주세요.

은 '입니다.Classtype 파라미터를 범용 타입의 생성자로 변환합니다(예:

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

클래스 패스에 의존하지 않고 직접 할 수 있는 방법을 찾고 있었습니다.조사해 본 결과, 범용 슈퍼 타입만 있으면 가능하다는 것을 알았습니다.범용 레이어 슈퍼 타입의 DAO 레이어로 작업하고 있었기 때문에, 이 점에서는 문제가 없었습니다.이것이 시나리오에 맞는다면 IMHO에서 가장 깔끔한 접근법입니다.

지금까지 접한 대부분의 범용 사용 사례에는 다음과 같은 일반적인 슈퍼타입이 있습니다. List<T>★★★★★★에ArrayList<T> ★★★★★★★★★★★★★★★★★」GenericDAO<T>★★★★★★에DAO<T> 등등.

순수 자바 솔루션

"Java 런타임일반 유형에 액세스" 문서에서는 순수 Java를 사용하여 일반 유형을 액세스하는 방법을 설명합니다.

@SuppressWarnings("unchecked")
public GenericJpaDao() {
  this.entityBeanType = ((Class) ((ParameterizedType) getClass()
      .getGenericSuperclass()).getActualTypeArguments()[0]);
}

스프링 솔루션

제 프로젝트는 스프링을 이용한 것이었는데 스프링은 유형을 찾는 편리한 유틸리티 방법이 있어서 더욱 좋습니다.이게 제일 깔끔해 보여서 저한테는 가장 좋은 방법이에요.스프링을 사용하지 않았다면 자신만의 유틸리티 방법을 작성할 수 있었을 것입니다.

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

풀코드 예시

어떤 사람들은 이것을 작동시키기 위해 코멘트에 어려움을 겪고 있기 때문에, 저는 두 가지 방법을 모두 보여주기 위해 작은 애플리케이션을 작성했습니다.https://github.com/benthurley82/generic-type-resolver-test

작은 . 즉, 자신의 허점을 하면, '허점'이 있습니다.이러한 허점을 정의하면Foo추상적인 수업입니다., 을 다음과 같이 . : , 、 음 、 래 、 음 、 음 음 、 음 음 that that that

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

(마지막에 있는 이중 괄호를 주의해 주세요).

, 그럼 이제 이 글자의 할 수 .T「 」:

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

, 「」, 「」는 해 주세요.mySuperclass.클래스 정의의 최종 을 실제로 합니다.T.

우아한 , 어떤 이 더 좋은지, 어떤 것이 더 좋은지 .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다음과 같이 합니다.

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

일반적인 추상 슈퍼클래스가 있다고 가정해 보겠습니다.

public abstract class Foo<? extends T> {}

다음으로 Foo를 확장한 두 번째 클래스와 T:를 확장한 일반 막대가 있습니다.

public class Second extends Foo<Bar> {}

클래스는 수강할 수 .Bar.class에서 Foo를 Type에서) (bert bruynoog를 사용하여 합니다. 답변에서) 그리고 그것을 사용하여 추론합니다.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 클래스에서 호출된 경우 반환되는 값은 Bar.class입니다.

유효한 솔루션은 다음과 같습니다.

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

참고: 슈퍼클래스로만 사용할 수 있습니다.

  1. 클래스타입 클래스)로.Child extends Generic<Integer>)

또는

  1. 익명 구현으로 작성해야 합니다(new Generic<Integer>() {};

나는 추상 일반 수업 시간에 이 문제가 있었다.이 경우 솔루션은 다음과 같이 단순해집니다.

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

이후 파생 클래스:

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

대부분의 답변과 달리 가능합니다(외부 라이브러리 없이도 가능).

다음은 이 문제에 대한 저의 (어색하지만 효과적인) 솔루션입니다.

import java.lang.reflect.TypeVariable;


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

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

// Generic helper class which (only) provides type information. This avoids
// the usage of a local variable of type T, which would have to be initialized.
private final class __<T> {
    private __() { }
}

활자가 지워져서 할 수 없어요.Stack Overflow 질문 Java generics - type erasure - 언제, 어떻게 되는지도 참조하십시오.

다른 사용자가 제안한 클래스보다 더 나은 경로는 클래스로 수행할 수 있는 개체를 전달하는 것입니다. 예를 들어 새 인스턴스를 만드는 것입니다.

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

범용 클래스가 있기 때문에 다음과 같은 변수가 있을 것입니다.

private T t;

(이 변수는 생성자에서 값을 취해야 합니다.)

이 경우, 다음의 방법을 간단하게 작성할 수 있습니다.

Class<T> getClassOfInstance()
{
    return (Class<T>) t.getClass();
}

도움이 됐으면 좋겠다!

다음과 같은 가능성이 있습니다.

class Foo<T> {
  Class<T> clazz = (Class<T>) DAOUtil.getTypeArguments(Foo.class, this.getClass()).get(0);
}

hibernate-generic-dao/blob/master/dao/src/main/java/com/googlecode/genericdao/DA에서 두 가지 기능이 필요합니다.OUtil.java.

자세한 내용은 일반 정보 반영을 참조하십시오.

나는 그것을 할 수 있는 일반적이고 간단한 방법을 찾았다.클래스 정의의 위치에 따라 일반 유형을 반환하는 메서드를 만들었습니다.다음과 같은 클래스 정의를 가정합니다.

public class MyClass<A, B, C> {

}

다음으로 다음 유형을 유지하는 Atribute를 다음에 나타냅니다.

public class MyClass<A, B, C> {

    private Class<A> aType;

    private Class<B> bType;

    private Class<C> cType;

// Getters and setters (not necessary if you are going to use them internally)

    } 

그런 다음 일반 정의의 인덱스에 따라 유형을 반환하는 일반 메서드를 생성할 수 있습니다.

   /**
     * Returns a {@link Type} object to identify generic types
     * @return type
     */
    private Type getGenericClassType(int index) {
        // To make it use generics without supplying the class type
        Type type = getClass().getGenericSuperclass();

        while (!(type instanceof ParameterizedType)) {
            if (type instanceof ParameterizedType) {
                type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
            } else {
                type = ((Class<?>) type).getGenericSuperclass();
            }
        }

        return ((ParameterizedType) type).getActualTypeArguments()[index];
    }

마지막으로 컨스트럭터에서는 메서드를 호출하여 각 유형에 대한 인덱스를 전송합니다.전체 코드는 다음과 같습니다.

public class MyClass<A, B, C> {

    private Class<A> aType;

    private Class<B> bType;

    private Class<C> cType;


    public MyClass() {
      this.aType = (Class<A>) getGenericClassType(0);
      this.bType = (Class<B>) getGenericClassType(1);
      this.cType = (Class<C>) getGenericClassType(2);
    }

   /**
     * Returns a {@link Type} object to identify generic types
     * @return type
     */
    private Type getGenericClassType(int index) {

        Type type = getClass().getGenericSuperclass();

        while (!(type instanceof ParameterizedType)) {
            if (type instanceof ParameterizedType) {
                type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
            } else {
                type = ((Class<?>) type).getGenericSuperclass();
            }
        }

        return ((ParameterizedType) type).getActualTypeArguments()[index];
    }
}

다른 답변에서 설명한 바와 같이, 이것을 사용하려면ParameterizedType어프로치, 수업 연장이 필요하지만, 완전히 새로운 수업 연장을 위한 추가 작업인 것 같습니다.

따라서 클래스를 추상화하면 클래스를 확장하여 하위 분류 요건을 충족할 수 있습니다.(롬복의 @Getter 사용).

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

그것은 꽤 직설적이다.같은 클래스 내에서 필요한 경우:

Class clazz = this.getClass();
ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
try {
        Class typeClass = Class.forName( parameterizedType.getActualTypeArguments()[0].getTypeName() );
        // You have the instance of type 'T' in typeClass variable

        System.out.println( "Class instance name: "+  typeClass.getName() );
    } catch (ClassNotFoundException e) {
        System.out.println( "ClassNotFound!! Something wrong! "+ e.getMessage() );
    }

많은 사람들이 이 기술을 몰라요!사실, 오늘 막 발견했어요!꿈만 같아!이 예를 확인해 주세요.

public static void main(String[] args) {
    Date d=new Date();  //Or anything you want!
    printMethods(d);
}

public static <T> void printMethods(T t){
    Class<T> clazz= (Class<T>) t.getClass(); // There you go!
    for ( Method m : clazz.getMethods()){
        System.out.println( m.getName() );
    }
}
   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
        }
   }

제네릭스를 사용하고 있는 클래스/인터페이스를 확장 또는 실장하고 있는 경우는, 기존의 클래스/인터페이스를 전혀 변경하지 않고, 부모 클래스/인터페이스의 범용 타입을 취득할 수 있습니다.

있을 수 있어 3possibilities,.

사례 1언제 당신의 클래스는 제네릭을 사용하여 클래스를 확장하고 있다.

public class TestGenerics {
    public static void main(String[] args) {
        Type type = TestMySuperGenericType.class.getGenericSuperclass();
        Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
        for(Type gType : gTypes){
            System.out.println("Generic type:"+gType.toString());
        }
    }
}

class GenericClass<T> {
    public void print(T obj){};
}

class TestMySuperGenericType extends GenericClass<Integer> {
}

사례 2너의 클래스는 제네릭을 사용하는 인터페이스를 시행하고 있다.

public class TestGenerics {
    public static void main(String[] args) {
        Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces();
        for(Type type : interfaces){
            Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
            for(Type gType : gTypes){
                System.out.println("Generic type:"+gType.toString());
            }
        }
    }
}

interface GenericClass<T> {
    public void print(T obj);
}

class TestMySuperGenericType implements GenericClass<Integer> {
    public void print(Integer obj){}
}

너의 인터페이스 제네릭을 사용하는 인터페이스를 확장하고 있사례 3.

public class TestGenerics {
    public static void main(String[] args) {
        Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces();
        for(Type type : interfaces){
            Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
            for(Type gType : gTypes){
                System.out.println("Generic type:"+gType.toString());
            }
        }
    }
}

interface GenericClass<T> {
    public void print(T obj);
}

interface TestMySuperGenericType extends GenericClass<Integer> {
}

사실, 타입의 당신의 수업에 밭이 있으신가 보T.만약 형식 T의 필드 무슨 일이 일어나는지 제네릭 매개 변수 형식 쓰시게요?그래서, 단순히 그 분야에 대한 instanceof을 할 수 있다.

내 경우엔 난 a다

List<.T>조목;
in my class, and I check if the class type is "Locality" by

만약(items.get(0)instanceof어서 전통 및 지역성을 음...

가능하면 수업의 총 수를 제한된다 물론, 이것으로만 작동합니다.

이 질문은 오래되었지만, 지금 가장 좋은 것은 구글을 사용하는 것이다.Gson.

커스텀을 취득하는 예viewModel.

Class<CustomViewModel<String>> clazz = new GenericClass<CustomViewModel<String>>().getRawType();
CustomViewModel<String> viewModel = viewModelProvider.get(clazz);

제네릭 형식 클래스

class GenericClass<T>(private val rawType: Class<*>) {

    constructor():this(`$Gson$Types`.getRawType(object : TypeToken<T>() {}.getType()))

    fun getRawType(): Class<T> {
        return rawType as Class<T>
    }
}

나는 제네릭이 이용한 메서드에 T.class을 통과하길 원했다.

메서드 readFile.csv 파일 fullpath으로 액세스에 의해 지정된 읽는다.내용이 다른 csv 파일이 있을 수 있으므로 모델 파일 클래스를 통과해야 적절한 오브젝트를 얻을 수 있습니다.일반적인 방법으로 csv 파일을 읽고 싶었기 때문에.어떤 이유에서인지 위의 해결책 중 어느 것도 나에게는 효과가 없었다.사용할 필요가 있다Class<? extends T> type파일의 합니다.CSV opencsv 。

private <T>List<T> readFile(String fileName, Class<? extends T> type) {

    List<T> dataList = new ArrayList<T>();
    try {
        File file = new File(fileName);

        Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
        Reader headerReader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));

        CSVReader csvReader = new CSVReader(headerReader);
        // create csv bean reader
        CsvToBean<T> csvToBean = new CsvToBeanBuilder(reader)
                .withType(type)
                .withIgnoreLeadingWhiteSpace(true)
                .build();

        dataList = csvToBean.parse();
    }
    catch (Exception ex) {
        logger.error("Error: ", ex);
    }

    return dataList;
}

readFile 메서드는 이렇게 호출됩니다.

List<RigSurfaceCSV> rigSurfaceCSVDataList = readSurfaceFile(surfaceFileName, RigSurfaceCSV.class);

회피책을 사용하고 있습니다.

class MyClass extends Foo<T> {
....
}

MyClass myClassInstance = MyClass.class.newInstance();

언급URL : https://stackoverflow.com/questions/3437897/how-do-i-get-a-class-instance-of-generic-type-t

반응형