我遵循这段代码:
public <T extends ParentException> T managedException(Exception cause) {
if(ExceptionA.class.isInstance(cause)) {
return ExceptionA.class.cast(cause);
} else if(ExceptionB.class.isInstance(cause)) {
return ExceptionB.class.cast(cause);
} else if(ExceptionC.class.isInstance(cause)){
return ExceptionC.class.cast(cause);
} else {
return new ExceptionD(cause.getMessage(), cause);
}
}
Run Code Online (Sandbox Code Playgroud)
在这里ExceptionA,ExceptionB,ExceptionC,ExceptionD是儿童ParentException.
在编译时,我得到了错误:
incompatible types: ExceptionA cannot be converted to T
incompatible types: ExceptionB cannot be converted to T
incompatible types: ExceptionC cannot be converted to T
incompatible types: ExceptionD cannot be converted to T
Run Code Online (Sandbox Code Playgroud)
但是,如果我将代码更改为:
@SuppressWarnings("unchecked")
public <T extends ParentException> T managedException(Exception cause) {
if(ExceptionA.class.isInstance(cause)) {
return (T) ExceptionA.class.cast(cause);
} else if(ExceptionB.class.isInstance(cause)) {
return (T) ExceptionB.class.cast(cause);
} else if(ExceptionC.class.isInstance(cause)){
return (T) ExceptionC.class.cast(cause);
} else {
return (T) new ExceptionD(cause.getMessage(), cause);
}
}
Run Code Online (Sandbox Code Playgroud)
它没有编译错误.
正如SO线程的答案中所提到的:如何使方法返回类型通用?T允许转换,并在此线程中给出另一个指针:Java Generics:仅定义为返回类型的泛型类型.但我的问题是:为什么当T有界并且所有返回的对象都落入指定范围时,我需要使用类型转换?
你在做什么是错的.这就是你得到错误的原因.你可以用你的方法调用你的方法,ExceptionC exceptionC=managedException(ExceptionD d)你最终会得到一个(ExceptionC) exceptionD;强制转换,并且它会掩盖错误,但你会在运行时得到它.
将您的方法更改为:
public ParentException managedException(Exception cause) {
if(ExceptionA.class.isInstance(cause)) {
return ExceptionA.class.cast(cause);
} else if(ExceptionB.class.isInstance(cause)) {
return ExceptionB.class.cast(cause);
} else if(ExceptionC.class.isInstance(cause)){
return ExceptionC.class.cast(cause);
} else {
return new ExceptionD(cause.getMessage(), cause);
}
}
Run Code Online (Sandbox Code Playgroud)
你这里不需要泛型.所有这些异常也是ParentExceptions,因此您可以返回它们.当你考虑它时,你试图让方法返回不同的类型.这样做是不可能的,因为如果你有一个从这个方法初始化的变量,你需要知道结果是什么.而且您知道结果将是ParentException,但您无法知道哪种父异常.
它背后的原因是你的方法如果写得不是返回ParentException - 它返回T(一个子类).并且您可以返回不同类型的子类,而不是您要获取的子类.
在一个更简单的例子中,如果我们有:
class A {}
class B extends A{ };
class C extends A{ };
public <T extends A> T test() {
return (T) new B();
}
Run Code Online (Sandbox Code Playgroud)
我们可以调用它,C c=test();我们实际上尝试转换(C) new B();哪些是不兼容的但我们已经屏蔽它并且我们在运行时获得异常