Java通用对象初始化

时间:2013-11-16 20:21:55

标签: java generics object-initialization

请先看看这个片段:

public MultiThreadManager( Class<T> c) {
    T[] allJobs = (T[]) Array.newInstance( c , MAX_THREAD_SIZE ) ;
    for ( int i = 0 ; i < MAX_THREAD_SIZE ; i ++ ) {
        allJobs[i] = (T) new Object();
        service.submit( allJobs[i] );
        getWaitingThreads().add( allJobs[i] );
    }           
}

以下是例外:

Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to slave.JobTemplate

我想做什么:

MultiThreadManager的构造函数应该采用实现Callable的泛型类型(比如Job.java)。创建所有这些通用数据类型(Job,java)的数组。初始化它,以便通用数据类型(Job.java)的构造函数将在执行程序服务中运行并执行它们。

请帮我识别错误或建议更好的方式。

提前谢谢

谢谢大家,但事情稍微复杂一点: 以下是其他信息:

public class Job extends JobTemplate<String> {...details ...}
public abstract class JobTemplate< T > implements Callable<T> {...details..}

最后

MultiThreadManager< Job > threadManager = new MultiThreadManager< Job >( Job.class );

再次感谢:)

3 个答案:

答案 0 :(得分:5)

您需要更多反射,就像您需要创建数组一样:

allJobs[i] = c.newInstance();

并使用try-catch包围所有那些讨厌的检查异常。

但是,我建议使用new Callable[],因为没有必要深入了解实际工作类型的细节。您还应该考虑不需要反射的设计:调用者实例化作业而不是传入类对象。当前解决方案受限于仅通过默认构造函数实例化的Job类型。

答案 1 :(得分:3)

当你说new Object()时,会创建一个Object类的新对象。它的动态运行时类型是Object。因此,T的投射在逻辑上无效,除非T实际上是Object

创建T需要做的是使用反射来调用T上的相应构造函数。

答案 2 :(得分:2)

罗宾&amp; Marko展示了问题的根源,我还有一件事要强调,"Effective Java" By Joshua Bloch

  

第25项:首选列表
  ...   数组和泛型具有非常不同的类型规则。数组   协变和具体化;泛型是不变的和擦除的。作为一个   结果,数组提供运行时类型安全但不提供编译时   类型安全,反之亦然。一般来说,数组   和仿制药混合不好。如果你发现自己混合它们   得到编译时错误或警告,你的第一个冲动应该是   用列表替换数组。

<强>解释

协变 - 意味着,例如,对象数组是Array of Integer的超类型。泛型是不变的,意思是,你不能将List<Integeer>强加给List<Object>

Reified - 在编译期间 arrays 的所有信息在运行时也可用。泛型由 erasure 实现,这意味着它们的类型约束仅在编译时强制执行,然后擦除(在运行时它不存在)。

总结
使用泛型混合数组很可能会导致问题 - 尽量避免使用列表而不是数组来混合两者:

public <T> void MultiThreadManager(Class<T> c) 
                throws IllegalAccessException, InstantiationException {

    List<T> allJobs = new ArrayList<T>(MAX_THREAD_SIZE) ;
    for (int i = 0; i < MAX_THREAD_SIZE; i++) {
        allJobs.add(c.newInstance());
        service.submit( allJobs.get(i) );
        getWaitingThreads().add( allJobs.get(i));
    }
}