如何将非泛型接口扩展为泛型接口?

4

我正在尝试扩展TemporalAdjuster,使其看起来像这样:

public interface TypedTemporalAdjuster<T extends Temporal & Comparable<? super T>> {

    T adjustInto(T temporal);
}

当我尝试直接扩展基本接口时,

public interface TypedTemporalAdjuster<T extends Temporal & Comparable<? super T>>
        extends TemporalAdjuster {

    T adjustInto(T temporal);
}

我遇到了一个错误。

...java:名称冲突:...具有相同的擦除,但是没有一个覆盖另一个

有没有办法解决这个问题?

目前为止,我已经做了...

public interface TypedTemporalAdjuster<T extends Temporal & Comparable<? super T>> { //extends TemporalAdjuster {

    static <T extends Temporal & Comparable<? super T>> TypedTemporalAdjuster<T> of(
            final Class<T> temporalClass, final TemporalAdjuster temporalAdjuster) {
        return temporal -> temporalClass.cast(temporalAdjuster.adjustInto(temporalClass.cast(temporal)));
    }

    T adjustInto(T temporal);
}

1
我认为一个新的界面是正确的选择,就像你所做的那样。 - Glains
2
你可以使返回类型更具体,但如果你使参数类型更具体,那么你就不再覆盖该方法了。 - E.M.
1
也可以考虑覆盖继承的方法,然后添加一个新的抽象方法,将默认委托给它:@Override default Temporal adjustInto(Temporal temporal) { return adjustInto2((T) temporal); } T adjustInto2(T temporal);。这仍然是一个功能接口。 - ernest_k
1个回答

7
您不能使用更严格的参数覆盖一个方法,例如T adjustInto(T temporal);无法覆盖Temporal adjustInto(Temporal temporal);,因为参数类型TTemporal更严格。因此,现在您有两个名为adjustInto的方法,但由于类型擦除,在字节码级别上参数类型是相同的,因为T extends Temporal & Comparable<? super T>被擦除为Temporal
您可以通过更改声明来解决这个问题:
public interface TypedTemporalAdjuster<T extends Comparable<? super T> & Temporal>
extends TemporalAdjuster {
    T adjustInto(T temporal);
}

作为语义相同的 T extends Comparable<? super T> & Temporal 会被擦除为 Comparable 而不是 Temporal。你也可以使用 T extends Object & Comparable<? super T> & Temporal,它被擦除为 Object(通常,这种知识只有在需要与预泛型代码兼容时才相关)。
然而,根本问题仍然存在,adjustInto(T temporal); 没有覆盖 adjustInto(Temporal temporal); ,因为 T 是更严格的参数,所以现在接口不再是功能接口,因为它有两个抽象方法。 TemporalAdjuster 的子接口必须提供其所有操作,包括接受任何 TemporaladjustInto。所以你只能这样做:
public interface TypedTemporalAdjuster<T extends Temporal & Comparable<? super T>>
extends TemporalAdjuster {

    static <T extends Temporal & Comparable<? super T>> TypedTemporalAdjuster<T> of(
            final Class<T> temporalClass, final TemporalAdjuster temporalAdjuster) {
        return temporal -> temporalClass.cast(temporalAdjuster.adjustInto(temporal));
    }

    @Override T adjustInto(Temporal temporal);
}

然而,这样包装的调整器不能确保正确的参数,并且只是隐藏了类型转换,仍然可能在运行时失败。但似乎你在尝试解决一个不存在的问题,因为你可以简单地使用暂存的with方法来获得类型安全的操作,例如:
TemporalAdjuster a = TemporalAdjusters.lastDayOfMonth();

LocalDate     date1     = LocalDate.now(),     date2     = date1.with(a);
LocalDateTime dateTime1 = LocalDateTime.now(), dateTime2 = dateTime1.with(a);
ZonedDateTime zoned1    = ZonedDateTime.now(), zoned2    = zoned1.with(a);

这甚至比你的包装器更强大,因为当你这样做时,例如:
TemporalAdjuster a = TemporalAdjusters.ofDateAdjuster(date -> date.plusDays(1));

ZonedDateTime zoned1 = ZonedDateTime.now(), zoned2 = zoned1.with(a);

您仅需一次定义一个操作,使用 LocalDate 操作,即可通过在运行时将其转换而不是强制转换其他时间使其适用于其他时间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接