简体   繁体   中英

Java Class Cast Exception thrown even though the cast-from parent class is actually an instance of the cast-to subclass

I'm trying to cast a returned Thread object from Java's ThreadFactory.newThread(Runnable r) to a specific subclass of Thread which my Android application uses, as follows:

private ThreadFactory mvThreadSource = Executors.defaultThreadFactory();

...

//Invokes the thread factory's newThread(Runnable r) method 
//mvThreadsVector is an ArrayList<BackgroundThread>
//class BackgroundThread extends Thread and implements an interface
public void spawnBGThreads(int numThreads){
 for (int i=0;i<numThreads;i++){
  mvThreadsVector.add((BackgroundThread) mvThreadSource.newThread(new
  BackgroundThread())); 
 }
}

This throws a class cast exception, but I'm not sure why; I know I'm seemingly attempting to downcast which can't be done, but the Thread returned by mvThreadSource.newThread(new BackgroundThread()) should actually be an instance of BackgroundThread. To my understanding this should make it legal to 'downcast' as I attempt to above (because it shouldn't really be downcasting), but the Android runtime (targeting SDK revision 17) disagrees. What is illegal about the above cast? What alternative approach should I use (hopefully short of creating my own BackgroundThreadFactory class that extends ThreadFactory)?

ThreadFactory wraps a thread around a Runnable . So, it is creating some other kind of Thread that will call the run() method of your BackgroundThread when it starts.

Probably what you want to do is to create your own ThreadFactory implementation that creates BackgroundThread s.

but the Thread returned by mvThreadSource.newThread(new BackgroundThread()) should actually be an instance of BackgroundThread

What makes you think that?

What makes you think it's a good idea to pass in an instance of Thread to ThreadFactory.newThread in the first place? In some cases, creating Thread instances without starting them can actually lead to memory leaks, I believe. (Quite possibly not on Android, mind you.)

There's a reason why the parameter for ThreadFactory.newThread is of type Runnable instead of Thread - it's only meant to be "the action that should be run" rather than a thread. It's the ThreadFactory 's job to create the thread to run the action - that's why it's called ThreadFactory :)

You could create your own ThreadFactory which created BackgroundThread instances, but it's not clear why you want to do so in the first place. What's your actual requirement here? Perhaps you should actually not be building a List<BackgroundThread> but instead List<BackgroundRunnable> where BackgroundRunnable is an interface which extends Runnable and has whatever extra methods you want on it...

No, ThreadFactory.newThread returns a Thread:

class SimpleThreadFactory implements ThreadFactory {
    public Thread newThread(Runnable r) {
        return new Thread(r);
    }
}

A Thread, as returned by newThread, is not a BackGroundThread --> ClassCastException in your code.

Note that the newThread's input parameter takes a Runnable. Your BackGroundThread is a Runnable, but newThread is not meant to accept Threads. It should accept Runnables that will be wrapped into a Thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM