2014-04-07 71 views
1

我有其簽名的方法:如果我想噸至是Class<String>如果我有麻煩Java:我如何指定一個類方法參數的類?

String str = isA(String.class); 

是:

Class<String> cls = isA(???); 

public static <T> T isA(Class<T> clazz); 

所以我能做到這一點

我不知道如何制定參數isA()。任何人都可以提供指導?

如果你想知道爲什麼我想這樣做,我使用EasyMock來模擬一個需要Class<T>參數的類。


編輯:我被要求添加一個我想要做的例子。

我試圖用EasyMock來模擬Solr的SolrCore類作爲測試用例的一部分。 SolrCore的方法之一的簽名是:

public <T extends Object> T createInitInstance(PluginInfo info, Class<T> cast, String msg, String defClassName); 

隨着EasyMock我可以設置該方法的期望。將構建isA(PluginInfo.class),例如,告訴EasyMock的匹配類PluginInfo的任何對象:

QueryParserPlugin queryPlugin = createNiceMock(QueryParserPlugin.class); 
SolrCore core = createNiceMock(SolrCore.class); 

expect(core.createInitInstance(
    isA(PluginInfo.class), isA(xxx), 
    anyString(), anyString())).andReturn(queryPlugin); 

我的問題告訴isA()匹配Class<T>類,其中T在這種情況下是QueryParserPlugin的任何對象。

+4

基本上,你沒有。沒有'Class >'。 –

+1

也許你應該向我們展示你正在努力完成的一個例子。 –

+2

不是我認爲它會工作,但我很好奇,如果你通過'String.class.getClass()'作爲參數會發生什麼。 – jaco0646

回答

2

反射和java的問題是類型擦除。你只需要給編譯器一個提示。

由於您期望的對象是T類型的,而且方法本身是通用的,所以您必須讓java知道您真正在使用哪種類型。

它所需要的只是一點提示,在運行時可以通過保存該類型信息的編譯方法傳遞。

所以在編譯的時候你有需要的方法:

Class<String> 

編譯器只知道編譯型,所以完全不知道該類型本身是一個類定義,使其無法分配,如果你不告訴java什麼類型的任務是。

所以此工程:

Class<String> myVar = String.class; 

或者這樣工作的:

Class<String> myVar = isA(String.class); 

或者這個作品

public <T> T myMethod(Class<T> object) 

Class<String> class = myMethod(String.class) 

但這不起作用

public <T> void myMethod(Class<T> object); 

,因爲我們沒有爲泛型賦值T.

那麼你如何讓編譯器知道T真的是一個類?

public <T> void myClassWrapper(Class<? super T> object); 

myMethod(myClassWrapper(String.class)); 

所以將其通過接受你讓編譯器知道在最低限度,這件事是一個類,它代表叔在T自己的層次結構的某些部分的方法,從而讓該方法編譯。

或你當然可以永遠只是做

myMethod((Class<String>)string.class)); 

,但我認爲是有點個人的hackish。我不是那些沒有表現出來並且用方法包裹的演員的粉絲。

由於您無法控制測試框架的簽名,您可以讓java知道您的意圖。

我不確定這是多麼容易的模擬工作,但繼承人測試有點幫助解釋發生了什麼事情。

@Test 
public void testCreation(){ 
    Object integer = 5; 
    String myString = "A String"; 
    int five = typeTheObject(Integer.class, integer); 
    Class<String> stringClass = typeTheObject(myString); 
    Class<Integer> myInt = typeTheObject(five); 
    Class<?> myClass = typeTheObject(String.class); 
    TypeValidator typeValidator = new TypeValidator(stringClass); 
    typeValidator.isA(typeTheObject(String.class)); 
} 

public static class TypeValidator{ 
    private final Object objectToValidate; 
    public TypeValidator(Object object){ 
     objectToValidate = object; 
    } 

    public <T> T isA(T type){ 
     if(objectToValidate.getClass().isAssignableFrom(type.getClass())){ 
      return type; 
     }else{ 
      Assert.fail(); 
      return null; //cuase 
     } 
    } 
} 

public static <T> Class<T> typeTheObject(Class<? super T> type){ 
    return (Class<T>)type; 
} 

public static <T> T typeTheObject(Class<T> type, Object object){ 
    if(object.getClass().isAssignableFrom(type)){ 
     return (T)object; 
    } 
    return (T)object; 
} 

public static <T> Class<T> typeTheObject(Object object){ 
    return (Class<T>)((T)object).getClass(); 
} 

雖然一大缺點是參數化類型。但是這些可以使用guice類型文字來解決。

(new TypeLiteral<List<String>(){}).getRawType(); 

自從它的annon類型在運行時保持。

相關問題