Java Generic object initialization

2019-08-31 11:38发布

Please look at this snippet first :

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] );
    }           
}

Here is the exception :

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

What I am trying to do :

The Constructor of MultiThreadManager should take a generic type ( say Job.java ) which implements Callable. Create array of all those generic data type ( Job,java ) . Initialize it so the constructor of generic data type ( Job.java ) will run and execute them in a executor service.

Please help me identify my error or please suggest a better way.

Thank You in advance

Thanks you all , but things are little more complex : Herez the other information :

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

and finally

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

Again thanks :)

3条回答
在下西门庆
2楼-- · 2019-08-31 11:48

When you say new Object(), that creates a new object of class Object. Its dynamic, run-time type is Object. So the cast to T wouldn't be logically valid, unless T is in fact Object.

What you would need to do to create a T is use reflection to invoke the appropriate constructor on T.

查看更多
Anthone
3楼-- · 2019-08-31 11:52

Robin & Marko showed the source of the issue, and I have one more thing to stress out, from "Effective Java" By Joshua Bloch:

Item 25: Prefer lists to arrays
... arrays and generics have very different type rules. Arrays are covariant and reified; generics are invariant and erased. As a consequence, arrays provide runtime type safety but not compile-time type safety and vice versa for generics. Generally speaking, arrays and generics don’t mix well. If you find yourself mixing them and getting compile-time errors or warnings, your first impulse should be to replace the arrays with lists.

Explanation:

Covariant - means, for example, that Array of Objects is supertype of Array of Integer. Generics are invarient, means, you can't cast a List<Integeer> to a List<Object>

Reified - all the information that exists for arrays during compile-time is also available during run-time. Generics are implemented by erasure which means that their type constraints is enforced only during compile-time and then erased (it doesn't exist during run-time).

To sum up:
Mixing arrays with generics will most likely cause you problems - try to avoid mixing the two by using Lists instead of arrays:

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));
    }
}
查看更多
虎瘦雄心在
4楼-- · 2019-08-31 12:07

You'll need more reflection, just as you need to create the array:

allJobs[i] = c.newInstance();

and surround with try-catch for all those pesky checked exceptions.

However, I would suggest using new Callable[] because there's no need to go into the specifics of the actual job type. You should also consider a design where reflection is unnecessary: the caller instantiates the jobs instead of passing in the class object. The current solution suffers from the restriction on the Job type to be instantiated only through the default constructor.

查看更多
登录 后发表回答