简体   繁体   English

如何基于Java中的类参数实例化泛型类

[英]How to instantiate a generic class based on class parameters in Java

How do I instantiate a new generic class based on class parameters? 如何基于类参数实例化新的泛型类? My main class looks as follows: 我的主要课程如下:

public class ServiceTransformer<SERVICE_I, SERVICE_O> extends Loggable {

private Class<SERVICE_I> serviceInputClass;
private Class<SERVICE_O> serviceOutputClass;

public ServiceTransformer(Logger logger, String inputXslt, String outputXslt, String appRoot) {
    try {
        serviceInputClass = (Class<SERVICE_I>) getGenericTypeClass(0);
        serviceOutputClass = (Class<SERVICE_O>) getGenericTypeClass(1);
    } catch (BadConfigurationException ex) {
        LOGGER.error("@@@ ConfigBase() Constructor Exception => ", ex);
    } catch (MalformedURLException ex) {
        LOGGER.error("@@@ ConfigBase() Constructor Exception => ", ex);
    }
}

private Type getGenericTypeClass(int index) {
    try {
        return ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[index];
    } catch (Exception ex) {
        LOGGER.error("@@@ getGenericTypeClass() Exception => ", ex);
    }
    return null;
}
}

And I instantiate a new ServiceTransformer class as follows: 我实例化一个新的ServiceTransformer类,如下所示:

ServiceTransformer<ReactivatePrepaidSubscriberInput, ReactivatePrepaidSubcriberOutput> service = 
                new ServiceTransformer<ReactivatePrepaidSubscriberInput, ReactivatePrepaidSubcriberOutput>(
                        LOGGER, inputFile, outputFile, APPROOT);

The error that I am currently getting is java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType 我目前得到的错误是java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

No idea where I am going wrong. 不知道我哪里错了。

It is only possible to get the generic type arguments from the superclass, just as you are doing it: 它只能从超类中获取泛型类型参数,就像您在执行它一样:

return ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()

But your ServiceTransformer does not extend a generic class, only Loggable , which is not generic, hence cannot be cast to ParameterizedType . 但是你的ServiceTransformer没有扩展泛型类,只有Loggable ,它不是通用的,因此不能转换为ParameterizedType

The trick you could do would be to instantiate an anonymous subclass of ServiceTransformer : 你可以做的伎俩是实例化ServiceTransformer的匿名子类:

new ServiceTransformer<In, Out>(LOGGER, inputFile, outputFile, APPROOT) {};

(note the {} at the end) (注意最后的{}

That would allow access to the generic type arguments of the superclass - this time the superclass is the ServiceTransformer class itself. 这将允许访问超类的泛型类型参数 - 这次超类是ServiceTransformer类本身。

However, note that every time you use this anonymous class construct, a new class is created by the compiler which may affect the performance of your application. 但请注意,每次使用此匿名类构造时,编译器都会创建一个新类,这可能会影响应用程序的性能。

If you are often using a fixed set of <In, Out> types, create a proper top-level named subclass for it and reuse that, as suggested in other answers. 如果您经常使用一组固定的<In, Out>类型,请为其创建适当的顶级命名子类,并重用该类,如其他答案中所建议的那样。 Eg. 例如。

class StringIntTransformer extends ServiceTransformer<String, Integer>

if you use the combination often. 如果你经常使用这种组合。

The main problem is that generic type arguments can be retrieved only from an inheritance context, you can see it clearly from the method name: 主要问题是泛型类型参数只能从继承上下文中检索,您可以从方法名称中清楚地看到它:

getGenericSuperclass()

This means that you need to instantiate a subtype of ServiceTransformer<I,O> to be able to query for the type arguments. 这意味着您需要实例化ServiceTransformer<I,O>的子类型才能查询类型参数。

This can be done in two ways, you can have a custom real type as 这可以通过两种方式完成,您可以使用自定义实际类型

public static class MyServiceTransformer extends ServiceTransformer<ReactivatePrepaidSubscriberInput,ReactivatePrepaidSubcriberOutput>
{
  MyServiceTransformer()
  {
    super(...);
  }
}

Or you can define it anonymously: 或者您可以匿名定义它:

new ServiceTransformer<ReactivatePrepaidSubscriberInput, ReactivatePrepaidSubcriberOutput>(....){}

First you need a deeper inheritance. 首先,您需要更深层次的继承。

public abstract class AbstractServiceTransformer<SERVICE_I, SERVICE_O> extends Loggable {

private Class<SERVICE_I> serviceInputClass;
private Class<SERVICE_O> serviceOutputClass;

public ServiceTransformer(Logger logger, String inputXslt, String outputXslt, String appRoot) {
        serviceInputClass = TypeUtils.getParametrizedType(this.getClass(),0)
        serviceOutputClass = TypeUtils.getParametrizedType(this.getClass(),1)
}

...
}

Then here your actual implementation. 然后在这里实际实施。

public class ServiceTransformer extends AbstractServiceTransformer<Service1, Service2> {
    ...
}

After that you can read class of type parameters like this. 之后,您可以像这样读取类型参数类。

public final class TypeUtils {

    /**
     * Returns parameterized type as a Class.
     */
    public static <T> Class<T> getParametrizedType(Class<?> baseClass, int index) {
        final Type genericSuperClass = baseClass.getGenericSuperclass();

        if (!(genericSuperClass instanceof ParameterizedType)) {
            throw new IllegalArgumentException("Your super class need to have a parameterized type");
        }

        final ParameterizedType parameterizedType = (ParameterizedType) genericSuperClass;
        final Type[] types = parameterizedType.getActualTypeArguments();

        if (types[index] instanceof Class<?>) {
            return (Class<T>) types[index];
        } else {
            throw new IllegalArgumentException("Parameter type is mismatched");
        }

    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM