2015-09-01 120 views
1

如何基於類參數實例化新的泛型類? 我的主類看起來如下:如何基於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

只可能從超獲得泛型類型參數,就像你正在做它:

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> 

如果您經常使用該組合。

+0

解決了!你會建議如何處置這些新創建的匿名類? –

+0

這是不可能的 - 它們是在編譯期間生成的(你會看到它們是'SurroundingClass $ 1.class','SurroundingClass $ 2.class'等等),一旦它們被加載,它們就會留在內存中。但我不會擔心它,除非你正在創建數以千計的匿名類。如果您經常使用一組固定的''類型,請爲其創建適當的頂級命名子類並重復使用它,如其他答案中的建議。例如。如果經常使用組合,類StringIntTransformer擴展了ServiceTransformer 。 –

0

的主要問題是,泛型類型參數只能從一個繼承的上下文檢索,可以從方法的名稱清楚地看到它:

getGenericSuperclass() 

這意味着你需要實例化的ServiceTransformer<I,O>一個子類型能夠查詢類型參數。

這可以通過兩種方式來完成,你可以有一個自定義的真正類型

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

或者你可以匿名進行定義:

new ServiceTransformer<ReactivatePrepaidSubscriberInput, ReactivatePrepaidSubcriberOutput>(....){} 
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"); 
     } 

    } 

}