简体   繁体   中英

Class.asSubclass with multiple bounded types and unchecked cast

I have a class which is generified with the type <T extends Enum<T> & Runnable> . I have a member variable Class<T> bar which I set by the class name: t = (Class<T>) Class.forName(name) . This gives me an unchecked cast warning.

Normally, using asSubclass can be used in similar situations, but since T has multiple bounds, I'm not able to use it without getting a compiler warning:

//This is type safe, but I still get an unchecked cast warning
t = (Class<T>) Class.forName(className).asSubclass(Enum.class).asSubclass(Runnable.class);

Can I get rid of this warning in any way, without using @SupressedWarning("unchecked") ?

Full example:

public class Example<T extends Enum<T> & Runnable> {
    Class<T> t;

    Example(String className) throws ClassNotFoundException {
        t = (Class<T>) Class.forName(className).asSubclass(Enum.class).asSubclass(Runnable.class);
    }
}
//This is type safe, but I still get an unchecked cast warning
t = (Class<T>) Class.forName(className).asSubclass(Enum.class).asSubclass(Runnable.class);

Whoa, slow down a second! Is that actually true? No it's not! All you've done is establish that the class matching the passed-in name is both a Runnable and an Enum , not that it is actually T . You've only validated the bounds. Imagine we had classes T1 and T2 :

package foo;
public enum T1 implements Runnable {
    ;
    @Override
    public void run() {
    }
}

package foo;
public enum T2 implements Runnable {
    ;
    @Override
    public void run() {
    }
}

Then this works fine, but is obviously not type safe:

Example<T1> example = new Example<T1>("foo.T2");
Class<T1> t1Clazz = example.t; //uh oh...

This isn't a problem of multiple bounds either. You'd have the same problem with only one bound.

As @sp00m mentions, the real solution is probably to pass in Class<T> here.

Edit

If, on the other hand, T was only needed internally (ie to specify the multiple bounds) and need not actually be exposed, then another option is to maintain the class in two separate references. For example:

Class<? extends Runnable> runnableClass;
Class<? extends Enum> enumClass;

Example(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    Class<?> clazz = Class.forName(className);
    runnableClass = clazz.asSubclass(Runnable.class);
    enumClass = clazz.asSubclass(Enum.class);
}

That's because, without the type parameter, there are very few circumstances where you could actually take advantage of the knowledge that it's an enum and a Runnable at the same time. If you create an instance of the class, you need to assign it to a variable/field of type Runnable or Enum ; you can't do both.

我相信你根本不能......我认为最好的解决方案是直接将Class<T> clazz作为参数传递而不是它的String name

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