请先看看这个片段:
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 );
再次感谢:)
答案 0 :(得分:5)
您需要更多反射,就像您需要创建数组一样:
allJobs[i] = c.newInstance();
并使用try-catch包围所有那些讨厌的检查异常。
但是,我建议使用new Callable[]
,因为没有必要深入了解实际工作类型的细节。您还应该考虑不需要反射的设计:调用者实例化作业而不是传入类对象。当前解决方案受限于仅通过默认构造函数实例化的Job类型。
答案 1 :(得分:3)
当你说new Object()
时,会创建一个Object类的新对象。它的动态运行时类型是Object。因此,T
的投射在逻辑上无效,除非T
实际上是Object
。
创建T
需要做的是使用反射来调用T
上的相应构造函数。
答案 2 :(得分:2)
第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));
}
}