Java 动态分派、重载和泛型

Java 动态分派、重载和泛型,java,generics,dispatch,Java,Generics,Dispatch,使用此类: public class Fallible<T> { private final Exception exception; private final T value; public Fallible(final T value) { this.value = value; this.exception = null; } public Fallible(final Exception exce

使用此类:

public class Fallible<T> {

    private final Exception exception;
    private final T value;

    public Fallible(final T value) {
        this.value = value;
        this.exception = null;
    }

    public Fallible(final Exception exception) {
        this.value = null;
        this.exception = exception;
    }

}
公共类易出错{
私人最终例外;
私人最终T值;
公众易犯错误(最终T值){
这个值=值;
this.exception=null;
}
公共易出错(最终例外){
this.value=null;
this.exception=异常;
}
}

我可以安全地假设
value
从不包含异常对象吗

不,你不能做出这样的假设。例如:

Object obj = new Exception();
Fallible f = new Fallible(obj);
将调用泛型构造函数

检查这一点的唯一方法是使用
instanceof
显式检查
值的类型:

public Fallible(final T value) {
  if (value instanceof Exception) {
    this.exception = (Exception) value;
    this.value = null;
  } else {
    this.value = value;
    this.exception = null;
  }
}
不,你不能

如果您考虑运行时得到的类型的擦除版本:

,这将更容易分析。
public Fallible(最终T值)
变为
public Fallible(最终java.lang.Object值)

因此,如果重载
Fallible(最终异常)
更匹配,则将使用它;i、 e.如果
异常
属于
异常
类型或其子类


在java中,构建一个允许从
java.lang.Object
构造但禁止从子类构造(在编译时)的类是不可能的。您必须依赖于运行时检查(
instanceof
&c)。顺便说一下,你可以用C++在C++中解决这个问题。在这一点以及其他许多方面,java被认为是C++的进化,是一个向前迈进一步又回到两步的例子。

注意到,在这个例子中,将异常扩展到Obj/<代码>等同于信息的丢失,也有相反的可能:<代码>新的错误(新的运行时异常)()。
现在还将调用泛型构造函数,因为它比显式构造函数更具体。也许这是故意的。正确的解决方案是删除重载的
public
构造函数,并使用具有不同名称的工厂方法,例如
value(T)
异常(Exception)
允许调用者记录意图并消除对
实例的需要。这些工厂方法不添加任何假设,即“
value
永远不会包含异常对象”:您仍然可以调用
Fallible.value(new Exception())
Fallible.value(obj)
。如果该类需要作出规定的假设,则有必要进行
instanceof
检查,作为防御措施。如果它是一个公共类,你就不能相信它的用户会做正确的事情来设置它的不变量。@Holger实际上,我希望
value(t)
exceptive(Exception)
都是
Fallible
@cuichtlauac类型,然后你可以调用
Fallible.Exception(…)
@cuihtlauac:这并不矛盾。在异常情况下,
T
可以是调用者想要的任何内容,因为没有实际值:
publicstaticfallibleexcellective(异常e){…}
。与返回一个
可选值的
进行比较。