通过交集类型具有附加约束的通用参数

Jen*_*ens 5 java generics

我正在编写一个表示时间序列数据的类,即基本上(Instant, T)是泛型类型的对映射T

interface TimeSeries<T> {
     void add(Instant when, T data);
}
Run Code Online (Sandbox Code Playgroud)

我们处理的一些类实现了一个接口

interface TimeStamped {
    Instant getTimeStamp();
}
Run Code Online (Sandbox Code Playgroud)

我想在TimeSeries界面中提供一个更方便的方法来添加这些数据项而不说明时间明确.基本上,我想要

interface TimeSeries<T> {
     void add(Instant when, T data);
     default <X extends T & TimeStamped> void add(X data) {
         add(data.getTimeStamp(), data);   
     } 
}
Run Code Online (Sandbox Code Playgroud)

但这似乎不被语言所允许,因为我不能在交集类型中使用类型变量.是否存在不涉及放弃静态类型安全的解决方法?我能想到的唯一的事情是

interface TimeSeries<T> {
     void add(Instant when, T data);
     default void add(TimeStamped data) {
         add(data.getTimeStamp(), (T)data);   
     }
     default void add(TimeStamped t, T data) {
         add(t.getTimeStamp(), data);
     } 
}
Run Code Online (Sandbox Code Playgroud)

add(TimeStamped t, T data) 是类型安全但仍然不方便.

Vla*_*sec 1

我想我明白你的问题。基本上,您可以拥有TimeSeries一些不实现 的简单类型TimeStamped,但它的一些子类实现了。在这些情况下,即使 @assylias 的解决方法也无济于事。

好吧,我认为 Java 8 中没有针对这个问题的干净解决方案,而且我没有使用 Java 9 的经验,但在阅读其新功能时我没有注意到类似的情况。这意味着您要么牺牲静态类型的安全性,要么牺牲舒适性。

很难说出什么是最好的解决方法。基本上到目前为止我们所拥有的是:

  • 仅时间戳接口,适用于您的基础对象已经实现该接口的情况TimeStamped,如 @assylias 所建议。
  • @cppbeginner 建议的静态方法。虽然我不喜欢这种语法,它意味着语法糖,但最终会得到静态调用。它的用途非常广泛,并且可以满足您的需求。
  • 完全放弃语法糖的想法,像奴隶一样打字。
  • 放弃类型安全并拥有可能适得其反的漂亮代码。
  • 哦等等,还有一种可能。使其成为接口方法TimeStamped,并以TimeSeries作为参数。实际上比静态更好,但有点自下而上。

我无法决定哪一个更适合您,因为我不知道您的用例。它们都不是完美的。我已经遇到过这个问题,但也没有找到超级智能的解决方案。我无法做的另一件事是通用枚举。我的意思是,为什么不呢,如果可能的话那就很有趣了(但也不是)。