我有两种方法:
public <T extends Component> void addComponent(BluePrint bluePrint, Class<T> type) throws InstantiationException, IllegalAccessException {
AddComponent addComponent = addComponentMap.get(type);
if (addComponent == null) {
addScriptable(bluePrint, type); <--- fails here
}
}
如果addComponentMap.get(type);
返回null,我就知道T的类型是Scriptabe,需要调用:
private <T extends Scriptable> void addScriptable(BluePrint bluePrint, Class<T> type) throws InstantiationException, IllegalAccessException {
scriptableSystems.add(new ScriptableSystem<T>());
}
问题是,第二个方法中T的上界是可脚本化的,而在第一个方法中它是Component,因此当addComponent为null时,类型"可能"可能是任何组件。
当addComponent为null时,我能以某种方式将约束缩小到Scriteable吗?或者以某种方式明确表示,当addComponent为null时,T将在调用addScriptable之前扩展Scriptable?
也许值得一提的是,Scriptable继承自组件。
问题是第二种方法中T的上界是Scriptable,并且在第一个方法中是它的Component,因此键入当addComponent为null时,"可能"可能是任何组件。
这差不多是对的,但我更强烈地说:由于Scriptable
扩展了Component
(而不是相反),方法addComponent()
中的类型参数T
可以始终是不受Scriptable约束的类型。
当addComponent为无效的
当然。假设你不想在其他情况下有更严格的界限,这就是铸造的目的:
public <T extends Component> void addComponent(BluePrint bluePrint, Class<T> type)
throws InstantiationException, IllegalAccessException {
AddComponent addComponent = addComponentMap.get(type);
if (addComponent == null) {
addScriptable(bluePrint, (Class<? extends Scriptable>) type);
}
}
您当然会收到一个关于强制转换的编译器警告。这是正确的,因为代码依赖于编译器无法验证的条件。
或者以某种方式明确表示,当addComponent为null时,T将在调用addScriptable之前扩展Scriptable?
这正是你通过选角所做的所说的。引用类型的值的强制转换实际上是一种断言,即您对该值的运行时类型的了解比编译器所能证明的要多。
此外,如果您希望具有不同于ClassCastException
:的过滤行为,则可以执行运行时测试
if (!Scriptable.class.isAssignableFrom(type)) {
throw new MyChosenException();
}
如果不能缩小映射中类的泛型类型,则仍然可以强制转换。为了更安全,您可以使用Class.isAssigneableFrom
,它是类(而不是对象)的实例:
public static void main(String[] args) {
Map<String, Class<? extends Number>> map = new HashMap<>();
Class<? extends Number> someNumberClass = map.get("Double");
if (Integer.class.isAssignableFrom(someNumberClass)) {
acceptInteger((Class<Integer>) someNumberClass);
}
}
public static void acceptInteger(Class<Integer> c) { }
这甚至不需要null检查,并且可以适用于addComponent
不为null的情况。在你的例子中,你会做:
if (Scriptable.class.isAssignableFrom(type)) { // add the null check if necessary
addScriptable(bluePrint, (Class<Scriptable>) type);
}