请先看看这个片段:
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 );
再次感谢:)
您将需要更多的反射,就像您需要创建数组一样:
allJobs[i] = c.newInstance();
并用 try-catch 包围所有这些讨厌的检查异常。
但是,我建议使用new Callable[]
因为没有必要深入了解实际工作类型的细节。您还应该考虑不需要反射的设计:调用方实例化作业而不是传入类对象。当前解决方案受到只能通过默认构造函数实例化的 Job 类型的限制。
当你说new Object()
时,会创建一个类对象的新对象。其动态运行时类型为"对象"。因此,T
的演员阵容在逻辑上是无效的,除非T
实际上是Object
。
创建T
需要做的是使用反射在T
上调用适当的构造函数。
Robin & Marko 展示了问题的根源,我还有一件事要强调,来自 Joshua Bloch 的"Effective Java":
第 25 项:首选列表而不是数组
... 数组和泛型具有非常不同的类型规则。阵 列 是协变和统一的;泛型是不变的,并且会被擦除。作为一个 因此,数组提供运行时类型安全,但不提供编译时安全性 泛型的类型安全,反之亦然。一般来说,数组 泛型不能很好地混合。如果您发现自己混合了它们并且 收到编译时错误或警告,您的第一个冲动应该是 将数组替换为列表。
解释:
协变 - 表示,例如,对象数组是整数数组的超类型。泛型是不变的,这意味着您不能将List<Integeer>
转换为List<Object>
已化 - 编译时数组存在的所有信息在运行时也可用。泛型是通过擦除实现的,这意味着它们的类型约束仅在编译时强制执行,然后被擦除(它在运行时不存在)。
总结一下:
将数组与泛型混合使用很可能会给您带来问题 - 尽量避免使用 Lists 而不是数组来混合两者:
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));
}
}