繁体   English   中英

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM