您仍然可以使用泛型方法,如下所示:
public class SomeException {
private final Object target;
public SomeException(Object target) {
this.target = target;
}
public <T> T getTarget() {
return (T) target;
}
}
....
catch (SomeException e) {
Integer target = e.getTarget();
}
我同意上面克里斯蒂安的回答。虽然公认的答案在技术上是正确的(就它引用 JVM 规范而言),但 Cristian Vasile 的答案是符合甚至挑战限制的答案。
我在对这个问题的回答中指出了至少两个我不同意并且我将反驳的论点。如果这些答案中的论点是正确的,我们可以使用这些论点在今天成功使用它们的其他上下文中攻击泛型。
第一个论点表明我们不能使用它:
catch (Exception<T1> e) {}
因为 JVM 不知道如何使用Exception<T1>
. 这个论点似乎也攻击了泛型的这种使用,因为 JVM 不知道如何使用List<T1>
:
List<T1> list;
当然,该论点忘记了编译器执行类型擦除,因此 JVM 不需要知道如何处理Exception<T1>
. 它可以简单地处理Exception
,就像它处理一样List
。
当然,由于类型擦除,我们永远无法在同一个 try/catch 中处理catch(Exception<T1> e)
和catch(Exception<T2> e)
,但话又说回来,这并不比今天使用方法参数或返回值更糟糕:我们今天也不处理myMethod(List<T1>)
和myMethod(List<T2>)
......(我重申这一点在下面的第二个反驳中。)
第二个论点如下。我们不允许这样:
catch (Exception<T1> e) {}
因为这行不通:
catch (Exception<T1> e) {}
catch (Exception<T2> e) {}
好的,那为什么不禁止这个:
interface MyInterface {
Comparable<Integer> getComparable();
}
因为这不起作用:
interface MyInterface {
Comparable<Integer> getComparable();
Comparable<String> getComparable();
}
或这个:
interface MyInterface {
void setComparable(Comparable<Integer> comparable);
}
因为这不起作用:
interface MyInterface {
void setComparable(Comparable<Integer> comparable);
void setComparable(Comparable<String> comparable);
}
换句话说,为什么在大多数情况下不禁止泛型呢?
第二个论点忘记了,尽管我们不可能允许在这些上下文中擦除相同非泛型构造的不同泛型构造,但我们仍然可以做次优的事情并允许泛型,只要类型不擦除为同一类型。这就是我们对方法参数所做的事情:我们允许您使用泛型,但一旦我们在类型擦除后检测到重复签名就会抱怨。好吧,我们可以用异常和 catch 块做同样的事情......
总之,我会扩展克里斯蒂安的答案。而不是允许通用异常类并catch
在块中使用原始类型:
class MyException<T> {}
...
catch (MyException e) { // raw
Java 本可以毫无问题地一路走好:
class MyException<T> {}
...
catch (MyException<Foo> e) {