Java:我如何指定一个类方法参数的类? [英] Java: How do I specify a class of a class method argument?

查看:258
本文介绍了Java:我如何指定一个类方法参数的类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个方法,其签名是:

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

所以我可以这样做:

  String str = isA(String.class); 

如果我想T是 Class< String>

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

我不确定如何将参数表达为 isA()。任何人都可以提供指导吗?



如果您想知道为什么要这样做,我使用EasyMock来模拟一个需要 Class 参数。





编辑:我被要求添加一个我的例子试图做。



我试图用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);
$ b $ expect(core.createInitInstance(
isA(PluginInfo.class),isA(xxx),
anyString(),anyString()))andReturn(queryPlugin);

我的问题是告诉 isA()匹配类 Class 中的任何对象,其中T在本例中为QueryParserPlugin。

解决方案

反射和java的问题是类型擦除。您只需要给编译器一个提示。



由于您期望的对象是T类型的,而且方法本身是通用的,所以您必须
让java知道你真的在用什么类型。

它需要的只是一点提示,在运行时可以通过编译方法传递该类型的信息。



所以在编译时你有一个方法可以接受:

 类<字符串> 

编译器只知道编译类型,所以不知道类型本身是类定义,如果你不告诉java什么类型的任务是不可能的。



所以这个工作:

  Class< String> myVar = String.class; 

或者这样做:

 类<字符串> myVar = isA(String.class); 

或者这可以工作

  public< T> T myMethod(Class< T>对象)

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

但这不起作用

 公共< T> void myMethod(Class< T> object); 

因为我们没有为泛型分配T。



所以你怎么让编译器知道T真的是一个类?

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

myMethod(myClassWrapper(String.class));

所以通过传递一个方法来接受你让编译器知道至少这个东西是一个类,它代表T在T自己层次结构的某个部分,从而让该方法编译。



或者当然你总是可以做

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

但我认为这有点不好。我不是一个不会使用explcit和包裹在方法中的模型的粉丝。

由于您无法控制测试框架的签名,您可以让java知道您的意图。



我不确定这是多么容易的模拟工作,但继承人测试有助于解释发生了什么。

  @Test 
public void testCreation(){
Object integer = 5;
String myString =一个字符串;
int five = typeTheObject(Integer.class,integer);
Class< String> stringClass = typeTheObject(myString);
Class< Integer> myInt = typeTheObject(五);
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();
返回null; // cuase
}
}
}

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

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

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

虽然一个很大的缺点是参数化类型。但是可以使用guice类型的文字来解决这些问题。

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

,因为它的annon类型在运行时保持不变。


I have a method whose signature is:

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

So I can do this:

String str = isA(String.class);

Where I'm having trouble is if I want T to be Class<String>:

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

I'm not sure how to formulate the argument to isA(). Can anyone offer guidence?

In case you're wondering why I want to do this, I'm using EasyMock to mock a class that takes a Class<T> argument.


EDIT: I was asked to add an example of what I'm trying to do.

I'm trying to use EasyMock to mock Solr's SolrCore class as part of a test case. The signature of one of SolrCore's methods is:

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

With EasyMock I can set up an expectation for that method. The construct isA(PluginInfo.class), for example, tells EasyMock to match any object of class PluginInfo:

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

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

My problem is telling isA() to match any object of class Class<T>, where T in this case is QueryParserPlugin.

解决方案

The issue with reflection and java is type erasure. You just need to give the compiler a hint.

Since the object you are expecting is of type T, and the method itself is generic, you kinda have to let java know what type you really are working with.

All it needs is a bit of a hint, something during runtime that can be passed through a compiled method that holds that type information.

So at compile time you have a method that takes in:

Class<String>

the compiler only knows the compiled type, so has no clue that the type itself is a class definition, making it impossible to assign if you don't tell java what the type of the assignment is.

So this works:

Class<String> myVar = String.class;

Or this works:

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

Or this works

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

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

but this doesn't work

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

since we have no assignment of T for the generic.

so how do you let the compiler know that T really is a class?

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

myMethod(myClassWrapper(String.class));

so by passing it through a method that accepts you let the compiler know that at minimum that this thing is a class and that it represents T at some part of T's own hierarchy, thus letting the method compile.

or of course you could always just do

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

but I think thats kinda hackish personally. I am not a fan of casts that are not explcit and wrapped in a method.

Since you cannot control the signature of the test framework, you can however let java know your intentions.

I am not sure how easy mock works, but heres a test to kinda help explain whats going on.

@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();
}

Though one big drawback is paramaterized types. But those can be solved using a guice type literal.

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

since its annon the type holds during runtime.

这篇关于Java:我如何指定一个类方法参数的类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆