可以构造泛型类型的通用方法

时间:2013-02-27 12:49:50

标签: java generics

我将测试用例添加到测试套件中,如下所示:

for(String methodName : getPublicDeclaredMethods(TestA.class))
{
    this.addTest((new TestA(methodName)));
}

for(String methodName : getPublicDeclaredMethods(TestB.class))
{
    this.addTest((new TestB(methodName)));
}

这相当于这样做:

this.addTest((new TestA("TEST_METHOD_1")));
this.addTest((new TestA("TEST_METHOD_2")));
this.addTest((new TestB("TEST_METHOD_1")));
this.addTest((new TestB("TEST_METHOD_3")));  // woops I forgot TEST_METHOD_2

我坚持使用这个奇怪的测试框架,其中方法名称通过构造作为字符串提供。

我上面的代码保证我添加在特定类中定义的所有测试用例。但是,我希望有一个看起来像这样的方法:

void <T> addTestCasesFromClass()
{
    for(String methodName : getPublicDeclaredMethods(T.class))
    {
        this.addTest((new T(methodName)));
    }
}

但我不确定这是如何在Java中完成的。它甚至可能吗? TestA和TestB派生自Test。

4 个答案:

答案 0 :(得分:1)

泛型在这里没用,因为你不能做new T之类的事情。但你可以用更多的反思来做到这一点。鉴于您传递给此方法的所有类都具有一个构造函数,该构造函数只接受一个String参数。

void addTestCasesFromClass(Class<?> clz)
{
     for(String methodName : getPublicDeclaredMethods(clz))
     { 
         this.addTest(clz.getConstructor(String.class).newInstance(methodName));
     }
}

电话会看起来像这样

addTestCasesFromClass(TestA.class); 
addTestCasesFromClass(TestB.class);

如果您的addTest方法只接受某个基类的对象(让它为TestBase),则将clz的通用参数更改为Class<? extends TestBase> clz

答案 1 :(得分:1)

当您只引用Generic类型时,无法实例化。 泛型仅在编译时可用,因此您无法在运行时使用它们。 这意味着您将需要对实际类Class的引用,并通过反射实例化它。

Class<?> clazz = ...
Object instance = clazz.newInstance();

虽然鼓励使用getConstructor。

这方面的一个很好的例子是java中的List.toArray方法,它要求你传递一个数组实例,这样它才能实际引用Class,因为泛型在运行时不可用。

答案 2 :(得分:1)

您可以使用反射来查找您传递的接受字符串参数的类的构造函数。然后使用您检索的方法名称实例化您的类。

public <T> void addTestClassesFromClass(T item){
    try {
        Constructor<?> constructor = item.getClass().getConstructor(String.class);
        for(String methodName : getPublicDeclaredMethods(item.getClass())){
            this.addTest((constructor.newInstance(methodName)));
        }
    } catch (Exception e) {
        System.out.println("Oh crap!");
    }
}

答案 3 :(得分:0)

这是我的尝试:

public void addTestCasesFromClass(Class<? extends Test> c) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
{
    for(String methodName : getPublicDeclaredMethods(c))
    {
        this.addTest((c.getDeclaredConstructor(String.class).newInstance(methodName)));
    }
}