Как я могу расширить не универсальный интерфейс в универсальный? - PullRequest
0 голосов
/ 30 августа 2018

Я пытаюсь расширить 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: name clash: ... имеют такое же стирание, но ни один не переопределяет другой

Есть ли способ сделать это?

Пока что я сделал.

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 Ответ

0 голосов
/ 30 августа 2018

Нельзя переопределить метод с более ограничивающими параметрами, т. Е. T adjustInto(T temporal); не переопределяет Temporal adjustInto(Temporal temporal);, поскольку тип параметра T является более строгим, чем Temporal. Итак, у вас есть два метода с именем 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 (обычно такие знания актуальны только тогда, когда вам нужна совместимость с кодом до Generics).

Однако основная проблема остается: adjustInto(T temporal); не переопределяет adjustInto(Temporal temporal);, поскольку T является более ограничительным параметром, поэтому теперь интерфейс больше не является функциональным интерфейсом, так как он имеет два абстрактных метода.

Подинтерфейс TemporalAdjuster должен обеспечивать все его операции, включая adjustInto, принимающий любые Temporal. Так что вы можете сделать только

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 манипуляции, в то время как она работает для других темпоралов, конвертируя их на лету, а не кастуя.

...