我有一个签名为:
的方法public static <T> T isA(Class<T> clazz);
所以我可以这样做:
String str = isA(String.class);
我遇到麻烦的地方是我想要T Class<String>
:
Class<String> cls = isA(???);
我不确定如何将论据制定为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。
答案 0 :(得分: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自己的层次结构的某个部分表示T,从而让方法编译。
当然你也可以随时做
myMethod((Class<String>)string.class));
但我认为这有点像个人。我不是那些没有explcit并用方法包装的演员的粉丝。
由于您无法控制测试框架的签名,因此您可以让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();
因为它的类型在运行时保持类型。