假设我们有:
abstract class Item { public Item(){}}
abstract class ExtraItem extends Item { public ExtraItem(){}}
class A extends Item{ public A(){}}
class B extends Item{ public B(){}}
class C extends Item{ public C(){}}
class EA extends ExtraItem{ public A(){}}
class EB extends ExtraItem{ public B(){}}
class EC extends ExtraItem{ public C(){}}
我想写这样的工厂类但没有强制转换:
class Factory {
Item createItem(String className){
Class clazz = Class.forName(className);
return (Item) clazz.newInstance(); //I don't want here cast to Item
}
ExtraItem createExtraItem(String className){
Class<? extends ExtraItem> clazz = (Class<? extends ExtraItem>) Class.forName(className); // I don't want here cast to Extraitem
return clazz.newInstance();
}
}
我尝试按上面的方式编写(当然还有演员):
@SuppressWarnings("unchecked")
public static <T extends Item> T createItem(String protocolType) {
try {
String className = protocolType;
Class<?> clazz = Class.forName(className);
return (T) clazz.newInstance();
} catch (Exception e) {
Log.e("ItemFactory", "Lack key \"" + protocolType + "\" in map: " + e.getLocalizedMessage());
}
return null;
}
但是如何在这里使用Class.cast()方法?这是一个更好的方法吗?
答案 0 :(得分:1)
如果您只是不喜欢编译器警告,那么您可以使用Class.asSubclass
为您进行检查:
Class<? extends Item> clazz = Class.forName(className).asSubclass(Item.class);
ExtraItem
的原则相同。如果命名的类实际上不是ClassCastException
的子类,则会在运行时抛出Item
。
答案 1 :(得分:0)
在string中传递className时,无法避免强制转换。由于您没有类型,我将创建Class<?>
,而newInstance()
会生成Object
。
如果您不想强制转换,则应传递要创建实例的类的Class实例。
除了演员是正常的操作,所以避免它没有太大的意义。请记住,大多数代码都可以在您编程工作时运行。如果您确定传递的字符串可以创建继承Item
的类,那么您可以投射而不会产生任何意外后果。
答案 2 :(得分:0)
如果您不想将演员签名更改为:
class Factory {
<T extends Item> T createItem(Class<T> itemClass) {
try {
return itemClass.newInstance();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
<T extends ExtraItem> T createExtraItem(Class<T> itemClass) {
return createItem(item);
}
}