Class and static method Class.forName() drive m

2020-02-25 22:55发布

this code doesn't compile. I'm wondering what I am doing wrong:

private static Importable getRightInstance(String s) throws Exception {
 Class<Importable> c = Class.forName(s);
 Importable i = c.newInstance();
 return i;
}

where Importable is an interface and the string s is the name of an implementing class. The compiler says:

./Importer.java:33: incompatible types
found   : java.lang.Class<capture#964 of ?>
required: java.lang.Class<Importable>
  Class<Importable> c = Class.forName(format(s));

thanks for any help!

All the solutions

Class<? extends Importable> c = Class.forName(s).asSubclass(Importable.class);

and

Class<? extends Importable> c = (Class<? extends Importable>) Class.forName(s);

and

Class<?> c = Class.forName(format(s));
Importable i = (Importable)c.newInstance();

give this error (that i don't understand):

Exception in thread "main" java.lang.IncompatibleClassChangeError: class C1 
has interface Importable as super class

where C1 is actually implementing Importable (so it is theoretically castable to Importable).

5条回答
在下西门庆
2楼-- · 2020-02-25 23:20

Try:

Class<? extends Importable> klaz = Class.forName(s).asSubclass(Importable.class);

Here are some snippets to illustrate the problems:

Class<CharSequence> klazz = String.class; // doesn't compile!
// "Type mismatch: cannot convert from Class<String> to Class<CharSequence>"

However:

Class<? extends CharSequence> klazz = String.class; // compiles fine!

So for an interface, you definitely need the upper-bounded wildcard. The asSubclass is as suggested by doublep.

API links

  • <U> Class<? extends U> asSubclass(Class<U> clazz)
    • Casts this Class object to represent a subclass of the class represented by the specified class object. Checks that that the cast is valid, and throws a ClassCastException if it is not. If this method succeeds, it always returns a reference to this class object.

Related questions

See also

查看更多
来,给爷笑一个
3楼-- · 2020-02-25 23:30

The issue is Class.forName is a static method with the following definition

public static Class forName(String className) throws ClassNotFoundException

Therefore it is not a bound parameter type at all and compiler would definitely throw the cast warning here as it has no way to guarantee the string name of the class would always give you the implementation of the interface.

If you know for sure that the string name passed into the method would be an implementation of the interface you can use SuppressWarnings annotation. But I dont think ther eis any other cleaner way to use forName with generics

查看更多
Deceive 欺骗
4楼-- · 2020-02-25 23:31

Use a runtime conversion:

Class <? extends Importable>  c
    = Class.forName (s).asSubclass (Importable.class);

This will bark with an exception at runtime if s specifies a class that doesn't implement the interface.

查看更多
家丑人穷心不美
5楼-- · 2020-02-25 23:33

Something like this might do the trick:

Class<?> c1 = Class.forName(s);
Class<? extends Importable> c = c1.asSubclass(Importable.class);
return c.newInstance();

Beware of a ClassCastException or NoClassDefFound if you pass in the wrong thing. As @polygenelubricants says, if you can figure out some way to avoid Class.forName then so much the better!

查看更多
▲ chillily
6楼-- · 2020-02-25 23:37

where Importable is an interface and the string s is the name of an implementing class.

The compiler can't know that, hence the error.

Use a cast. It is easier to cast the constructed object (because that is a checked cast), than the class object itself.

Class<?> c = Class.forName(s);
Importable i = (Importable) c.newInstance();
return i;
查看更多
登录 后发表回答