![](/img/trans.png)
[英]How do I construct an object of a derived class in a method whose argument is a base class in Java?
[英]Java: How do I specify a class of a class method argument?
我有一个方法的签名是:
public static <T> T isA(Class<T> clazz);
所以我可以这样做:
String str = isA(String.class);
我遇到麻烦的地方是我是否希望T成为Class<String>
:
Class<String> cls = isA(???);
我不确定如何公式化isA()
的参数。 谁能提供指导?
如果您想知道为什么要这样做,我正在使用EasyMock来模拟带有Class<T>
参数的Class<T>
。
我正在尝试使用EasyMock模拟Solr的SolrCore类作为测试用例的一部分。 SolrCore方法之一的签名是:
QueryParserPlugin queryPlugin = createNiceMock(QueryParserPlugin.class);
SolrCore core = createNiceMock(SolrCore.class);
expect(core.createInitInstance(
isA(PluginInfo.class), isA(xxx),
anyString(), anyString())).andReturn(queryPlugin);
使用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。
反射和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));
但我认为那有点个人主义。 我不喜欢那些没有明确说明并且用某种方法包装的演员。
由于您无法控制测试框架的签名,因此可以让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();
由于其类型,该类型在运行时保留。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.