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

时间:2015-09-01 12:52:38

标签: java

如何基于类参数实例化新的泛型类? 我的主要课程如下:

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

我实例化一个新的ServiceTransformer类,如下所示:

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

我目前收到的错误是java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

不知道我哪里出错了。

3 个答案:

答案 0 :(得分:3)

只能从超类中获取泛型类型参数,就像你在做它一样:

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

但是您的ServiceTransformer不会扩展通用类,只会扩展Loggable,这不是通用的,因此无法转换为ParameterizedType

你可以做的伎俩是实例化ServiceTransformer的匿名子类:

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

(注意最后的{}

这将允许访问超类的泛型类型参数 - 这次超类是ServiceTransformer类本身。

但是,请注意,每次使用此匿名类构造时,编译器都会创建一个新类,这可能会影响应用程序的性能。

如果您经常使用一组固定的<In, Out>类型,请为其创建适当的顶级命名子类,并按照其他答案的建议重复使用。例如。

class StringIntTransformer extends ServiceTransformer<String, Integer>

如果您经常使用该组合。

答案 1 :(得分:0)

主要问题是泛型类型参数只能从继承上下文中检索,您可以从方法名称中清楚地看到它:

1 => [{"foo":1,"bar":23},{"foo":1,"bar":25}]
2 => [{"foo":2,"bar":24},{"foo":2,"bar":26},{"foo":2,"bar":27}]
3 => [{"foo":3,"bar":29}]

这意味着您需要实例化getGenericSuperclass() 的子类型才能查询类型参数。

这可以通过两种方式完成,您可以将自定义实际类型设为

ServiceTransformer<I,O>

或者您可以匿名定义:

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

答案 2 :(得分:0)

首先,您需要更深层次的继承。

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

...
}

然后是你的实际实现。

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

之后,您可以读取类似参数类。

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

    }

}