Java 强制转换到运行时确定的类

Java 强制转换到运行时确定的类,java,generics,reflection,casting,reification,Java,Generics,Reflection,Casting,Reification,我有一个方法fetchObjects(String),它将返回一个Contract业务对象数组。className参数告诉我应该返回什么类型的业务对象(当然在这种情况下这没有意义,因为我已经说过我将返回Contracts,但这基本上是我在实际场景中遇到的情况)。因此,我从某处获取条目集并加载集合条目的类(其类型由className指定) 现在我需要构造要返回的数组,所以我使用Set的toArray(T[])方法。使用反射,我为自己构建了一个空的数组。但是,这给了我一个静态类型的值Object!因

我有一个方法
fetchObjects(String)
,它将返回一个
Contract
业务对象数组。
className
参数告诉我应该返回什么类型的业务对象(当然在这种情况下这没有意义,因为我已经说过我将返回
Contract
s,但这基本上是我在实际场景中遇到的情况)。因此,我从某处获取条目集并加载集合条目的类(其类型由
className
指定)

现在我需要构造要返回的数组,所以我使用
Set
toArray(T[])
方法。使用反射,我为自己构建了一个空的数组。但是,这给了我一个静态类型的值
Object
!因此,接下来我需要将其转换为适当的类型,在本例中是
Contract[]
(请参见下面列表中的“带下划线的星号”部分)

我的问题是:是否有一种方法,以及如何像我在清单中所做的那样转换为
Contract[]
,但只通过
className
(或
entriesType
)确定数组元素的类型(
Contract
)?换句话说,我想做的基本上是这样的强制转换:
(entriesType[])valueWithStaticTypeObject
,其中entriesType将由通过
classname
参数指定的类替换,即
合同

这是天生不可能的,还是可以做到的?也许使用泛型

package xx.testcode;

import java.util.HashSet;
import java.util.Set;

class TypedArrayReflection {

    public static void main(String[] args) {
        try {
            Contract[] contracts = fetchObjects("Contract");
            System.out.println(contracts.length);
        } catch (ClassNotFoundException e) {}
    }

    static Contract[] fetchObjects(String className) throws ClassNotFoundException {
        Class<?> entriesType = Class.forName("xx.testcode."+className);
        Set<?> entries = ObjectManager.getEntrySet(className); 
        return entries.toArray( 
                (Contract[]) java.lang.reflect.Array.newInstance(
                /********/          entriesType, entries.size()) );
    }
}

class Contract { } // business object

class ObjectManager {
    static Set<?> getEntrySet(String className) {
        if (className.equals("Contract"))
            return new HashSet<Contract>();
        return null; // Error
    }
}

我需要做什么来消除注释中引用的编译器错误?我是否必须在我的
getEntrySet
方法的返回类型中指定
Set
,这样才能工作?感谢您的指点。

您可以使用类作为参数,而不是类名

   static <T extends Contract> T[] buildArray(Class<T> clazz){
     ArrayList<T> l=new ArrayList<T>();
     return l.toArray((T[]) java.lang.reflect.Array.newInstance(clazz, l.size()));
   }
static T[]buildArray(类clazz){
ArrayList l=新的ArrayList();
返回l.toArray((T[])java.lang.reflect.Array.newInstance(clazz,l.size());
}
编辑:(看完杨评论)

不,不能将泛型类型与变量的值一起使用。

那么为什么不使用

static <T> T[] buildArray(Class<T> clazz){
ArrayList<T> l=new ArrayList<T>();
return l.toArray((T[]) java.lang.reflect.Array.newInstance(clazz, l.size()));
}
static T[]buildArray(类clazz){
ArrayList l=新的ArrayList();
返回l.toArray((T[])java.lang.reflect.Array.newInstance(clazz,l.size());
}

注意。修改了上面的代码。

这非常令人印象深刻!但问题是,我不想硬编码地指定契约类(业务对象也可以是House或Pet,具体取决于方法参数className)。需要通过className参数确定正确的类。既然调用者必须知道他期望的对象类型,那么为什么不传入class对象而不是名称呢?我不知道这个名字有什么优势。我对Milhous的回答的评论。我想他可能希望泛型是基于“String className”的值,而不是类型化的/generics/class参数。在实际场景中,我需要使用反射来获取类型的名称,例如,我从反射中获取“Contract”,然后用这个名称加载类。您不能将类型转换为编译时未知的类型。类型转换是一个编译时问题。泛型只是一种参数化类型转换的方法,让编译器将类型信息从代码的一部分传播到另一部分。但是编译器仍然需要知道它。当类entriesType不是Contract的子类时,如何处理?entriesType不一定是Contract的子类型。它可以是宠物、朋友、爱好——任何你可能收藏的东西。在我的示例中,客户将拥有一组合同。
static <T> T[] buildArray(Class<T> clazz){
ArrayList<T> l=new ArrayList<T>();
return l.toArray((T[]) java.lang.reflect.Array.newInstance(clazz, l.size()));
}