제네릭 유형의 클래스를 결정하는 방법은 무엇입니까?
제네릭 클래스를 만들고 있으며 현재 사용중인 제네릭 유형의 클래스를 알아야하는 메서드 중 하나입니다. 그 이유는 내가 호출하는 메서드 중 하나가 이것을 인수로 기대하기 때문입니다.
예:
public class MyGenericClass<T> {
public void doSomething() {
// Snip...
// Call to a 3rd party lib
T bean = (T)someObject.create(T.class);
// Snip...
}
}
분명히 위의 예제는 작동하지 않으며 다음 오류가 발생합니다. 유형 매개 변수 T에 대한 잘못된 클래스 리터럴입니다.
내 질문은 : 누군가가 이것에 대한 좋은 대안이나 해결 방법을 알고 있습니까?
여전히 동일한 문제 : 일반 정보는 런타임에 지워지고 복구 할 수 없습니다. 해결 방법은 정적 메서드의 매개 변수에 클래스 T를 전달하는 것입니다.
public class MyGenericClass<T> {
private final Class<T> clazz;
public static <U> MyGenericClass<U> createMyGeneric(Class<U> clazz) {
return new MyGenericClass<U>(clazz);
}
protected MyGenericClass(Class<T> clazz) {
this.clazz = clazz;
}
public void doSomething() {
T instance = clazz.newInstance();
}
}
추악하지만 작동합니다.
이 솔루션을 지적했습니다.
import java.lang.reflect.ParameterizedType;
public abstract class A<B> {
public Class<B> g() throws Exception {
ParameterizedType superclass =
(ParameterizedType) getClass().getGenericSuperclass();
return (Class<B>) superclass.getActualTypeArguments()[0];
}
}
이것은 A
하위 클래스에 의해 구체적인 유형이 주어지면 작동합니다 .
new A<String>() {}.g() // this will work
class B extends A<String> {}
new B().g() // this will work
class C<T> extends A<T> {}
new C<String>().g() // this will NOT work
불행히도 Christoph의 서면 솔루션은 매우 제한된 상황에서만 작동합니다. [편집 : 나는 더 이상이 문장에 대한 내 추론을 기억하지 아래 주석과 가능성이 잘못 같이 : "이 우선 추상 클래스에서만 작업합니다 참고있다."] 다음 어려움 즉 g()
단지의 직접 서브 클래스에서 작동합니다 A
. 하지만 다음과 같이 수정할 수 있습니다.
private Class<?> extractClassFromType(Type t) throws ClassCastException {
if (t instanceof Class<?>) {
return (Class<?>)t;
}
return (Class<?>)((ParameterizedType)t).getRawType();
}
public Class<B> g() throws ClassCastException {
Class<?> superClass = getClass(); // initial value
Type superType;
do {
superType = superClass.getGenericSuperclass();
superClass = extractClassFromType(superType);
} while (! (superClass.equals(A.class)));
Type actualArg = ((ParameterizedType)superType).getActualTypeArguments()[0];
return (Class<B>)extractClassFromType(actualArg);
}
이것은 실제로 많은 상황에서 작동하지만 항상 그런 것은 아닙니다. 중히 여기다:
public class Foo<U,T extends Collection<?>> extends A<T> {}
(new Foo<String,List<Object>>() {}).g();
ClassCastException
여기서 유형 인수는 a Class
또는 a 가 아니기 때문에 를 던집니다 ParameterizedType
. 그것은 TypeVariable
T
. 그래서 이제 당신은 어떤 유형 T
을 의미 해야하는지 알아 내려고 애 쓰고있을 것 입니다.
합리적이고 일반적인 대답은 Nicolas의 초기 대답과 비슷한 것이라고 생각합니다. 일반적으로 클래스가 컴파일 타임에 알려지지 않은 다른 클래스의 객체를 인스턴스화해야하는 경우 해당 클래스의 사용자는 해당 클래스 리터럴 ( 또는 아마도 팩토리) 클래스에 명시 적으로 제네릭에만 의존하지 마십시오.
일반 객체의 클래스를 얻는 다른 방법을 찾습니다.
public Class<?> getGenericClass(){
Class<?> result =null;
Type type =this.getClass().getGenericSuperclass();
if(type instanceofParameterizedType){
ParameterizedType pt =(ParameterizedType) type;
Type[] fieldArgTypes = pt.getActualTypeArguments();
result =(Class<?>) fieldArgTypes[0];
}
return result;
}
Christoph의 솔루션에 대해 자세히 설명하겠습니다.
다음은 ClassGetter 추상 클래스입니다.
private abstract class ClassGetter<T> {
public final Class<T> get() {
final ParameterizedType superclass = (ParameterizedType)
getClass().getGenericSuperclass();
return (Class<T>)superclass.getActualTypeArguments()[0];
}
}
다음은 위의 클래스를 사용하여 제네릭 클래스의 유형을 찾는 정적 메서드입니다.
public static <T> Class<T> getGenericClass() {
return new ClassGetter<T>() {}.get();
}
사용법의 예로서 다음 방법을 만들 수 있습니다.
public static final <T> T instantiate() {
final Class<T> clazz = getGenericClass();
try {
return clazz.getConstructor((Class[])null).newInstance(null);
} catch (Exception e) {
return null;
}
}
그리고 다음과 같이 사용하십시오.
T var = instantiate();
T는 TypeTools를 사용하여 매우 쉽게 해결할 수 있습니다 .
Class<T> t = (Class<T>) TypeResolver.resolveRawArguments(
MyGenericClass.class, getClass());
공용 클래스 DatabaseAccessUtil {
EntityManagerFactory entitymanagerfactory;
EntityManager entitymanager;
public DatabaseAccessUtil() {
entitymanagerfactory=Persistence.createEntityManagerFactory("bookmyshow");
entitymanager=entitymanagerfactory.createEntityManager();
}
public void save (T t) {
entitymanager.getTransaction().begin();
entitymanager.persist(t);
entitymanager.getTransaction().commit();
}
public void update(T t) {
entitymanager.getTransaction().begin();
entitymanager.persist(t);
entitymanager.getTransaction().commit();
}
public void delete(T t) {
entitymanager.getTransaction().begin();
entitymanager.remove(t);
entitymanager.getTransaction().commit();
}
public Object retrieve(Query query) {
return query.getSingleResult();
}
//call the method - retrieve(object,requiredclass.class)
public Object retrieve(Object primaryKey,class clazz) throws Exception {
return entitymanager.find(clazz,primaryKey);
}
}
참고URL : https://stackoverflow.com/questions/182636/how-to-determine-the-class-of-a-generic-type
'programing tip' 카테고리의 다른 글
core.async 및 Functional Reactive Programming (+ Rx) 비교 (0) | 2020.12.09 |
---|---|
Gitlab CI를 사용하여 Java Maven 프로젝트를 빌드하는 방법은 무엇입니까? (0) | 2020.12.09 |
php.ini : 어느 것? (0) | 2020.12.09 |
닫힌 웹 앱에서 Chrome 또는 Firefox로 데스크톱 알림을 보내시겠습니까? (0) | 2020.12.09 |
미리 채워진 데이터베이스와 함께 Room Persistence Library를 사용하는 방법은 무엇입니까? (0) | 2020.12.09 |