【问题标题】:Dynamic dispatch, overloading and generics动态调度、重载和泛型
【发布时间】:2016-09-22 12:15:41
【问题描述】:

使用这个类:

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;
    }

}

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

【问题讨论】:

    标签: java generics dispatch


    【解决方案1】:

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

    Object obj = new Exception();
    Fallible f = new Fallible(obj);
    

    将调用泛型构造函数。

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

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

    【讨论】:

    • 请注意,虽然此示例将异常扩大到 Object 相当于丢失信息,但也有相反的可能:new Fallible&lt;RuntimeException&gt;(new RuntimeException()) 现在也将调用泛型构造函数,因为它是比显式构造函数更具体。也许这是故意的。正确的解决方案是删除重载的public 构造函数并使用具有独特名称的工厂方法,例如value(T)exceptionally(Exception) 允许调用者记录意图并消除对 instanceof 的需要。
    • 这些工厂方法在“value永远包含异常对象”的假设方面没有添加任何内容:您仍然可以调用Fallible.value(new Exception())Fallible.value(obj)。如果这个类需要做出陈述的假设,instanceof 检查作为防御措施是必要的。如果它是一个公共类,你根本不能相信它的用户会做正确的事情来设置它的不变量。
    • @Holger 实际上,我希望value(T)exceptionally(Exception) 都属于Fallible&lt;T&gt; 类型。
    • @cuihtlauac 然后你可以调用Fallible.&lt;T&gt;exceptionally(...)
    • @cuihtlauac:这并不矛盾。在特殊情况下,T 可以是调用者想要的任何东西,因为没有实际值:public static &lt;T&gt; Fallible&lt;T&gt; exceptionally(Exception e) { … }。与返回 Optional&lt;AnythingYouWant&gt;Optional.empty() 进行比较。
    【解决方案2】:

    不,你不能。

    如果您考虑运行时获得的类型擦除版本,则更容易分析:

    public Fallible(final T value) 变为 public Fallible(final java.lang.Object value)

    因此,如果匹配更好,将使用重载Fallible(final Exception exception);即如果exceptionException 类型或其子类。

    在 Java 中构建一个允许从 java.lang.Object 构造但禁止从子类构造(在编译时)的类是不可能的。您将不得不依赖运行时检查 (instanceof &c.)。顺便说一句,您可以使用模板在 C++ 中解决这个问题。在这方面以及许多其他方面,Java 当被视为 C++ 的演进时,是向前一步和后退两步的情况。

    【讨论】:

      猜你喜欢
      • 2012-04-12
      • 2012-01-20
      • 2017-05-13
      • 1970-01-01
      • 1970-01-01
      • 2015-01-16
      • 2013-06-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多